Created on 2026-03-27.00:00:00 last changed 2 weeks ago
Proposed resolution:
This wording is relative to N5032.
Modify [time.format] as indicated:
-1- Each formatter ([format.formatter]) specialization in the chrono library ([time.syn]) meets the Formatter requirements ([formatter.requirements]). The `parse` member functions of these formatters interpret the format specification as a chrono-format-spec according to the following syntax:
[…] The productions fill-and-align, width, and precision are described in [format.string]. Giving a precision specification in the chrono-format-spec is valid only for types that are specializations of `std::chrono::duration` for which the nested typedef-name `rep` denotes a floating-point type, and the precision specification doesn't take effects unless explicitly specified. For all other types, an exception of type `format_error` is thrown if the chrono-format-spec contains a precision specification. All ordinary multibyte characters represented by literal-char are copied unchanged to the output. […] -7- Unless otherwise specified, if the chrono-specs is omitted, the chrono object is formatted as if by streaming it to basic_ostringstream<charT> os with the formatting locale imbued and copying `os.str()` through the output iterator of the context with additional padding and adjustments as specified by the format specifiers. The precision specification is applied as if by os << fixed << setprecision(precision).
Modify Table 133 — "Meaning of conversion specifiers" [tab:time.format.spec] as indicated:
| Specifier | Replacement |
|---|---|
| […] | |
| %Q | The `duration`'s numeric value (as if extracted via `.count()`). The precision specification is applied on that numeric value. |
| […] | |
Currently, the formatter for chrono types handles fill-align-width-precision besides chrono specifications. On the one hand, the standard regulates in the second paragraph of [time.format] p1 that:
The productions fill-and-align, width, and precision are described in [format.string].
and in [time.format] p7:
Unless otherwise specified, if the chrono-specs is omitted, the chrono object is formatted as if by streaming it to basic_ostringstream<charT> `os` with the formatting locale imbued and copying `os.str()` through the output iterator of the context with additional padding and adjustments as specified by the format specifiers.
[Example 3:string s = format("{:=>8}", 42ms); // value of s is "====42ms"— end example]
which imply that the precision specification takes effects on the final formatted string. On the other hand, the next two statements in [time.format] p1 say that:
Giving a precision specification in the chrono-format-spec is valid only for types that are specializations of `std::chrono::duration` for which the nested typedef-name `rep` denotes a floating-point type. For all other types, an exception of type `format_error` is thrown if the chrono-format-spec contains a precision specification.
which imply that the precision specification takes effects on the underlying floating-point representation.
These two contradictory intentions make unnecessary confusion and divergence in different implementations. Given code example below:
std::chrono::duration<float> s = 10ms + 10us + 123ns;
std::print("from chrono {:.3} | from count {:.3%Q}\n", s);
It gives four different outputs in libstdc++, libc++, MS-STL and FMT (i.e. fmtlib/fmt; though it doesn't need to be standard-compliant, we list it here for comparison):
Implementation {0:.3} {0:.3%Q} libc++ "0.0" "0.010010123" libstdc++ "0.0100101s" "0.010010123" MS-STL "0.0100101s" "0.0100101" FMT "0.010s" "0.010"
To be specific, the current implementations are as follows:
No chrono-spec, with precision:
libc++: Strictly obey [time.format] p7, so the streamed string is truncated as if by `format("{:.3}", "0.0100101s")` and remains the first three characters.
libstdc++: Ignore the precision.
MS-STL: Ignore the precision.
FMT: Apply the precision on the underlying floating-point representation.
`%Q` spec, with precision:
libc++: Ignore the precision and format representation to string. Note that `format` will apply `to_chars` on floating-point numbers, which forms the shortest recoverable string so `0.010010123` is fully output.
libstdc++: Ignore the precision and format representation to string.
MS-STL: Ignore the precision, output count to stream, and format the streamed string. So it outputs 6 significant digits and gives `0.0100101`.
FMT: Apply the precision on the underlying floating-point representation.
To bridge the gap among implementations, the standard should explicitly specify the effects of precision. Since the current wording says that precision is only allowed for `duration` with floating-point representation, an intuitive solution is just applying precision on that representation. Otherwise (i.e. the precision is applied on the streamed string), other chrono types like `time_point` should be capable of handling that too, making current constraint seemingly unnecessary.
| History | |||
|---|---|---|---|
| Date | User | Action | Args |
| 2026-04-04 12:52:07 | admin | set | messages: + msg16245 |
| 2026-03-27 00:00:00 | admin | create | |