[PATCH v2] libstdc++: Skip locale in chrono operator<< for integer seconds precision

Tomasz Kaminski tkaminsk@redhat.com
Sun Aug 30 13:42:17 GMT 2026


Hi,

I was approved here
https://gcc.gnu.org/pipermail/gcc-patches/2026-August/726191.html.
Streambuf_sink series is one that are still waiting for review.

It seems I haven't pushed it, despite being sure I did so (I even wrote
that in the e-mail).
I have done it now, this time for sure:
https://gcc.gnu.org/cgit/gcc/commit/?id=9c40d80365f334e01f6e864e62ca9965841774cb

Thanks for double checking it, and letting me know
Tomasz

On Sun, Aug 30, 2026 at 1:33 PM Jonathan Wakely <jwakely.gcc@gmail.com>
wrote:

> He's waiting for me to approve it.
>
>
> On Sun, 30 Aug 2026, 10:16 Anlai Lu, <agicy@qq.com> wrote:
>
>> Hi Tomasz,
>>
>> Thanks for merging. I checked trunk but couldn't find the patch. Could
>> you confirm it was pushed, or give me the commit hash?
>>
>> Best regards,
>> Anlai
>>
>> > On Aug 4, 2026, at 14:33, Tomasz Kaminski <tkaminsk@redhat.com> wrote:
>> >
>> > Hi Anlai,
>> >
>> > Patch was merged, thanks again for doing it.
>> >
>> > Regards,
>> > Tomasz
>> >
>> > On Mon, Aug 3, 2026 at 6:17 PM Jonathan Wakely <jwakely@redhat.com>
>> wrote:
>> >
>> >
>> > On Mon, 27 Jul 2026 at 08:41, 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:
>> >
>> > OK with those changes, thanks.
>> >
>> >
>> > 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/20260830/3c8ce59a/attachment-0001.htm>


More information about the Libstdc++ mailing list