Title
Encoding of `duration` unit suffixes is incorrect for wide streams
Status
new
Section
[time.duration.io]
Submitter
Victor Zverovich

Created on 2026-09-27.00:00:00 last changed 1 week ago

Messages

Date: 2026-09-27.17:34:01

Proposed resolution:

This wording is relative to N5054.

  1. Modify [time.duration.io] as indicated:

    template<class charT, class traits, class Rep, class Period>
      basic_ostream<charT, traits>&
        operator<<(basic_ostream<charT, traits>& os, const duration<Rep, Period>& d);
    

    -1- Effects: Inserts the duration `d` onto the stream `os` as if it were implemented as follows:

    basic_ostringstream<charT, traits> s;
    s.flags(os.flags());
    s.imbue(os.getloc());
    s.precision(os.precision());
    s << d.count() << units-suffix;
    return os << s.str();
    

    where units-suffix depends onis a character sequence of `charT` determined by the type `Period::type` as follows. In the following list, each quoted character sequence denotes the corresponding STATICALLY-WIDEN<charT> character sequence: […]

    [Drafting note:

    (1) The existing list is unchanged, including:

    Otherwise, if `Period::type` is `micro`, it is implementation-defined whether units-suffix is `"μs"` (`"\u00b5\u0073"`) or `"us"`.

    (2) Since `%q` in [time.format] refers to the duration's unit suffix as specified in [time.duration.io], this change also specifies the appropriate `charT` representation for `%q`. ]

Date: 2026-09-27.00:00:00

[time.duration.io] specifies operator<< for `duration` as if by:

basic_ostringstream<charT, traits> s;
s.flags(os.flags());
s.imbue(os.getloc());
s.precision(os.precision());
s << d.count() << units-suffix;
return os << s.str();

For `Period::type` equal to `micro`, units-suffix is implementation-defined to be either `"μs"` (`"\u00b5\u0073"`) or `"us"`.

The type and encoding of units-suffix are not specified in terms of `charT`. In particular, if `"μs"` denotes an ordinary string literal, then for a wide stream the expression above inserts a `const char*` into a basic_ostream<wchar_t>. [ostream.inserters.character] specifies this operation by applying `out.widen()` to each individual `char`.

This does not perform transcoding. For example, when the ordinary literal encoding is UTF-8, the micro sign is represented by multiple char code units. Widening those code units individually does not produce the corresponding micro sign in the wide literal encoding.

For example:

std::wostringstream os;
os << std::chrono::microseconds{1};

should be able to produce:

1μs

when the implementation chooses the `μs` representation, but the current specification does not provide semantics that produce that result.

The same problem affects `%q` in [time.format], whose replacement is specified as "the duration's unit suffix as specified in [time.duration.io]".

This is similar to LWG 4522, which clarified that formatting to `wchar_t` requires transcoding rather than widening narrow code units.

The unit suffix should therefore be specified directly as a sequence of `charT`, using the literal encoding associated with `charT`.

History
Date User Action Args
2026-09-27 17:34:01adminsetmessages: + msg16627
2026-09-27 00:00:00admincreate