Thanks this looks good to me. I will handle merging it once approved, with adjustments to the changelog listed below:
On Mon, Jul 27, 2026 at 5:29 AM Anlai Lu <[email protected]> wrote: > When _Duration uses integer seconds precision (period::den == 1, > not floating-point), time_point formatting has no sub-second > digits and therefore no locale-dependent components. Add > __detail::__chrono_write_time that conditionally skips the locale > argument for integer-second time_points, eliminating the > format_to_n locale overload and the basic_format_context > locale member initialization. > > Also add [[__gnu__::__always_inline__]] to > __formatter_chrono::_M_subsecs to mitigate a small mixed-TU > inlining regression. > > libstdc++-v3/ChangeLog: > > * include/bits/chrono_io.h > (__detail::__chrono_write_time): New function that conditionally > skips locale for integer-second time_points. > (__formatter_chrono::_M_subsecs): Add __always_inline__. > (operator<< for hh_mm_ss): Use if constexpr to skip locale > for integer-second durations. > (operator<< for sys_time, utc_time, tai_time, gps_time, > file_time, local_time, zoned_time): Use __chrono_write_time. > Changed it to: * include/bits/chrono_io.h (__detail::__chrono_write_time): New function that conditionally skips locale for integer-second time_points. (__formatter_chrono::_M_subsecs): Add __always_inline__. (operator<<(basic_ostream<...>, const hh_mm_ss<_Duration>&)): Use if constexpr to skip locale for integer-second durations. (operator<<(basic_ostream<...>, const zoned_time<_Duration>&)) (operator<<(basic_ostream<...>, const sys_time<_Duration>&)) (operator<<(basic_ostream<...>, const utc_time<_Duration>&)) (operator<<(basic_ostream<...>, const tai_time<_Duration>&)) (operator<<(basic_ostream<...>, const file_time<_Duration>&)) (operator<<(basic_ostream<...>, const local_time<_Duration>&)): Use __chrono_write_time. (operator<<(basic_ostream<...>, const sys_days<_Duration>&)): Remove trailing semicolon. > Suggested-by: Tomasz Kamiński <[email protected]> > Changed the above to: Reviewed-by: Tomasz Kamiński <[email protected]> > Signed-off-by: Anlai Lu <[email protected]> > --- > Performance data (Xeon, -O2, core pinned, turbo off): > > den==1 types instructions branches > --------------- ------------ -------- > sys_time_s -5.0% -11.3% > utc_time_s -5.0% -11.3% > tai_time_s -5.0% -11.3% > gps_time_s -5.0% -11.3% > file_time_s -5.0% -11.3% > local_time_s -5.1% -11.3% > zoned_time_s -2.8% -5.3% > hh_mm_ss_s -7.1% -15.7% > > den!=1: > sys_time_ms +0.3% +0.6% > utc_time_ms +0.3% +0.6% > local_time_ms +0.3% +0.6% > hh_mm_ss_ms +0.4% +0.7% > > --- > libstdc++-v3/include/bits/chrono_io.h | 44 +++++++++++++++++++++------ > 1 file changed, 34 insertions(+), 10 deletions(-) > > diff --git a/libstdc++-v3/include/bits/chrono_io.h > b/libstdc++-v3/include/bits/chrono_io.h > index c5170368f..2cbd61ccd 100644 > --- a/libstdc++-v3/include/bits/chrono_io.h > +++ b/libstdc++-v3/include/bits/chrono_io.h > @@ -1656,6 +1656,7 @@ namespace __format > } > > template<typename _OutIter, typename _FormatContext> > + [[__gnu__::__always_inline__]] > _OutIter > _M_subsecs(const _ChronoData<_CharT>& __t, _OutIter __out, > _FormatContext& __ctx) const > @@ -3635,6 +3636,23 @@ namespace __detail > return std::__ostream_insert(__os, __s.data(), __s.size()); > } > > + // Wrapper around __chrono_write that skips locale for > + // integer-second time_points. > + template<size_t _BufSize, typename _TimePoint, typename _CharT, > + typename _Traits> > + [[__gnu__::__always_inline__]] > + inline basic_ostream<_CharT, _Traits>& > + __chrono_write_time(basic_ostream<_CharT, _Traits>& __os, > + const _TimePoint& __tp) > + { > + using _Duration = typename _TimePoint::duration; > + if constexpr (!treat_as_floating_point_v<typename _Duration::rep> > + && _Duration::period::den == 1) > + return __chrono_write<_BufSize>(__os, __tp); > + else > + return __chrono_write<_BufSize>(__os, __tp, __os.getloc()); > + } > + > } // namespace __detail > /// @endcond > > @@ -3740,7 +3758,7 @@ namespace __detail > operator<<(basic_ostream<_CharT, _Traits>& __os, > const weekday_last& __wdl) > { return __detail::__chrono_write<128>(__os, __wdl, __os.getloc()); } > - > + > template<typename _CharT, typename _Traits> > inline basic_ostream<_CharT, _Traits>& > operator<<(basic_ostream<_CharT, _Traits>& __os, const month_day& > __md) > @@ -3846,7 +3864,13 @@ namespace __detail > inline basic_ostream<_CharT, _Traits>& > operator<<(basic_ostream<_CharT, _Traits>& __os, > const hh_mm_ss<_Duration>& __hms) > - { return __detail::__chrono_write<64>(__os, __hms, __os.getloc()); } > + { > + if constexpr (!treat_as_floating_point_v<typename _Duration::rep> > + && _Duration::period::den == 1) > + return __detail::__chrono_write<64>(__os, __hms); > + else > + return __detail::__chrono_write<64>(__os, __hms, __os.getloc()); > + } > > #if _GLIBCXX_USE_CXX11_ABI || ! _GLIBCXX_USE_DUAL_ABI > /// Writes a sys_info object to an ostream in an unspecified format. > @@ -3866,7 +3890,7 @@ namespace __detail > inline basic_ostream<_CharT, _Traits>& > operator<<(basic_ostream<_CharT, _Traits>& __os, > const zoned_time<_Duration, _TimeZonePtr>& __t) > - { return __detail::__chrono_write<128>(__os, __t, __os.getloc()); } > + { return __detail::__chrono_write_time<128>(__os, __t); } > #endif > > template<typename _CharT, typename _Traits, typename _Duration> > @@ -3875,12 +3899,12 @@ namespace __detail > inline basic_ostream<_CharT, _Traits>& > operator<<(basic_ostream<_CharT, _Traits>& __os, > const sys_time<_Duration>& __tp) > - { return __detail::__chrono_write<64>(__os, __tp, __os.getloc()); } > + { return __detail::__chrono_write_time<64>(__os, __tp); } > > template<typename _CharT, typename _Traits> > inline basic_ostream<_CharT, _Traits>& > operator<<(basic_ostream<_CharT, _Traits>& __os, const sys_days& __dp) > - { return __detail::__chrono_write<32>(__os, __dp); }; > + { return __detail::__chrono_write<32>(__os, __dp); } > > template<typename _CharT, typename _Traits, typename _Duration, > typename _Alloc = allocator<_CharT>> > @@ -3914,7 +3938,7 @@ namespace __detail > inline basic_ostream<_CharT, _Traits>& > operator<<(basic_ostream<_CharT, _Traits>& __os, > const utc_time<_Duration>& __t) > - { return __detail::__chrono_write<64>(__os, __t, __os.getloc()); } > + { return __detail::__chrono_write_time<64>(__os, __t); } > > template<typename _CharT, typename _Traits, typename _Duration, > typename _Alloc = allocator<_CharT>> > @@ -3946,7 +3970,7 @@ namespace __detail > inline basic_ostream<_CharT, _Traits>& > operator<<(basic_ostream<_CharT, _Traits>& __os, > const tai_time<_Duration>& __t) > - { return __detail::__chrono_write<64>(__os, __t, __os.getloc()); } > + { return __detail::__chrono_write_time<64>(__os, __t); } > > template<typename _CharT, typename _Traits, typename _Duration, > typename _Alloc = allocator<_CharT>> > @@ -3982,7 +4006,7 @@ namespace __detail > inline basic_ostream<_CharT, _Traits>& > operator<<(basic_ostream<_CharT, _Traits>& __os, > const gps_time<_Duration>& __t) > - { return __detail::__chrono_write<64>(__os, __t, __os.getloc()); } > + { return __detail::__chrono_write_time<64>(__os, __t); } > > template<typename _CharT, typename _Traits, typename _Duration, > typename _Alloc = allocator<_CharT>> > @@ -4017,7 +4041,7 @@ namespace __detail > inline basic_ostream<_CharT, _Traits>& > operator<<(basic_ostream<_CharT, _Traits>& __os, > const file_time<_Duration>& __t) > - { return __detail::__chrono_write<64>(__os, __t, __os.getloc()); } > + { return __detail::__chrono_write_time<64>(__os, __t); } > > template<typename _CharT, typename _Traits, typename _Duration, > typename _Alloc = allocator<_CharT>> > @@ -4040,7 +4064,7 @@ namespace __detail > // _GLIBCXX_RESOLVE_LIB_DEFECTS > // 4257. Stream insertion for chrono::local_time should be constrained > requires requires(const sys_time<_Duration>& __st) { __os << __st; } > - { return __detail::__chrono_write<64>(__os, __lt, __os.getloc()); } > + { return __detail::__chrono_write_time<64>(__os, __lt); } > > template<typename _CharT, typename _Traits, typename _Duration, > typename _Alloc = allocator<_CharT>> > -- > 2.34.1 > >
