[PATCH v2] libstdc++: Skip locale in chrono operator<< for integer seconds precision
Tomasz Kaminski
tkaminsk@redhat.com
Mon Jul 27 10:12:58 GMT 2026
Adding libstdc++ mailing list.
On Mon, Jul 27, 2026 at 9:41 AM Tomasz Kaminski <tkaminsk@redhat.com> wrote:
> 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 <agicy@qq.com> 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 <tkaminsk@redhat.com>
>>
> Changed the above to:
> Reviewed-by: Tomasz Kamiński <tkaminsk@redhat.com>
>
>> Signed-off-by: Anlai Lu <agicy@qq.com>
>> ---
>> 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
>>
>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://gcc.gnu.org/pipermail/libstdc++/attachments/20260727/10b9ac5e/attachment-0001.htm>
More information about the Libstdc++
mailing list