This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of New status.
duration formatterSection: 30.12 [time.format] Status: New Submitter: Liang Jiaming Opened: 2026-03-27 Last modified: 2026-04-04
Priority: Not Prioritized
View other active issues in [time.format].
View all other issues in [time.format].
View all issues with New status.
Discussion:
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 30.12 [time.format] p1 that:
The productions fill-and-align, width, and precision are described in 28.5.2 [format.string].
and in 30.12 [time.format] p7:
Unless otherwise specified, if the chrono-specs is omitted, the chrono object is formatted as if by streaming it to
[Example 3:basic_ostringstream<charT>oswith the formatting locale imbued and copyingos.str()through the output iterator of the context with additional padding and adjustments as specified by the format specifiers.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 30.12 [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::durationfor which the nested typedef-namerepdenotes a floating-point type. For all other types, an exception of typeformat_erroris 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 30.12 [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.
Proposed resolution:
This wording is relative to N5032.
Modify 30.12 [time.format] as indicated:
-1- Each
[…] The productions fill-and-align, width, and precision are described in 28.5.2 [format.string]. Giving a precision specification in the chrono-format-spec is valid only for types that are specializations offormatter(28.5.6 [format.formatter]) specialization in the chrono library (30.2 [time.syn]) meets the Formatter requirements (28.5.6.1 [formatter.requirements]). Theparsemember functions of these formatters interpret the format specification as a chrono-format-spec according to the following syntax:std::chrono::durationfor which the nested typedef-namerepdenotes a floating-point type, and the precision specification doesn't take effects unless explicitly specified. For all other types, an exception of typeformat_erroris 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 tobasic_ostringstream<charT> oswith the formatting locale imbued and copyingos.str()through the output iterator of the context with additional padding and adjustments as specified by the format specifiers.
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. |
[…]
|
|