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.

4257. Stream insertion for chrono::local_time should be constrained

Section: 30.7.9 [time.clock.local] Status: New Submitter: Jonathan Wakely Opened: 2025-05-16 Last modified: 2025-05-16

Priority: Not Prioritized

View all issues with New status.

Discussion:

Stream insertion for chrono::local_time is defined in terms of conversion to chrono::sys_time, but not all chrono::sys_time specializations can be inserted into an ostream, because one of the overloads is constrained and the other requires convertibility to chrono::sys_days (see 30.7.2.3 [time.clock.system.nonmembers]).

This means the following code fails to compile:


#include <iostream>
#include <chrono>

template<typename T>
concept ostream_insertable = requires (std::ostream& o, const T& t) { o << t; };

using D = std::chrono::duration<double>;

int main() {
  if constexpr (ostream_insertable<std::chrono::sys_time<D>>)
    std::cout << std::chrono::sys_time<D>{};
  if constexpr (ostream_insertable<std::chrono::local_time<D>>)
    std::cout << std::chrono::local_time<D>{}; // FAIL
}
The first condition is false, because there's no overload that's suitable. The second is true, because the operator<< overload for chrono::local_time isn't constrained and so insertion appears to be valid. But actually trying to use it is ill-formed, because it tries to convert the local_time<D> to a sys_time<D> and then insert that, which isn't valid.

Proposed resolution:

This wording is relative to N5008.

  1. Modify 30.7.9 [time.clock.local] as indicated:

    
    template<class charT, class traits, class Duration>
      basic_ostream<charT, traits>&
        operator<<(basic_ostream<charT, traits>& os, const local_time<Duration>& lt);
    

    -?- Constraints: os << sys_time<Duration>{lt.time_since_epoch()} is a valid expression.

    -2- Effects:

     os << sys_time<Duration>{lt.time_since_epoch()};
    

    -3- Returns: os.