[PATCH v2 2/2] libstdc++: Lift chrono localized formatting to main chrono format loop [PR110739]
Tomasz Kaminski
tkaminsk@redhat.com
Thu Jun 26 12:30:24 GMT 2025
On Thu, Jun 26, 2025 at 2:13 PM Tomasz Kaminski <tkaminsk@redhat.com> wrote:
>
>
> On Thu, Jun 26, 2025 at 2:09 PM Jonathan Wakely <jwakely@redhat.com>
> wrote:
>
>> On 26/06/25 11:39 +0200, Tomasz Kamiński wrote:
>> >This patch extract calls to _M_locale_fmt and construction of the struct
>> tm,
>> >from the functions dedicated to each specifier, to main format loop in
>> >_M_format_to functions. This removes duplicated code repeated for
>> specifiers.
>>
>> Great, this is exactly what I wanted to do. Removing all the branches
>> to call _M_locale_fmt from each of the _M_xxx member functions makes
>> them smaller and potentially faster.
>>
>> >To allow _M_locale_fmt to only be called if localized formatting is
>> enabled
>> >('L' is present in chrono-format-spec), we provide a implementations for
>> >locale specific specifiers (%c, %r, %x, %X) that produces the same result
>> >as locale::classic():
>> > * %c is implemented as separate _M_c method
>> > * %r is implemented as separate _M_r method
>> > * %x is implemented together with %D, as they provide same behavior,
>> > * %X is implemented together with %R as _M_R_X, as both of them do not
>> include
>> > subseconds.
>>
>> Nice.
>>
>> >The handling of subseconds was also extracted to _M_subsecs function
>> that is
>> >used by _M_S and _M_T specifier. The _M_T is now implemented in terms of
>> >_M_R_X (printing time without subseconds) and _M_subs.
>> >
>> >The __mod responsible for triggering localized formatting was removed
>> from
>> >method handling most of specifiers, except:
>> > * _M_S (for %S) for which it determines if subseconds should be
>> included,
>> > * _M_z (for %z) for which it determines if ':' is used as separator.
>> >
>> > PR libstdc++/110739
>> >
>> >libstdc++-v3/ChangeLog:
>> >
>> > * include/bits/chrono_io.h
>> (__formatter_chrono::_M_use_locale_fmt):
>> > Define.
>> > (__formatter_chrono::_M_locale_fmt): Moved to front of the class.
>> > (__formatter_chrono::_M_format_to): Construct and initialize
>> > struct tm and call _M_locale_fmt if needed.
>> > (__formatter_chrono::_M_c_r_x_X): Split into separate methods.
>> > (__formatter_chrono::_M_c, __formatter_chrono::_M_r): Define.
>> > (__formatter_chrono::_M_D): Renamed to _M_D_x.
>> > (__formatter_chrono::_M_D_x): Renamed from _M_D.
>> > (__formatter_chrono::_M_R_T): Split into _M_R_X and _M_T.
>> > (__formatter_chrono::_M_R_X): Extracted from _M_R_T.
>> > (__formatter_chrono::_M_T): Define in terms of _M_R_X and
>> _M_subsecs.
>> > (__formatter_chrono::_M_subsecs): Extracted from _M_S.
>> > (__formatter_chrono::_M_S): Replaced __mod with __subs argument,
>> > removed _M_locale_fmt call, and delegate to _M_subsecs.
>> > (__formatter_chrono::_M_C_y_Y, __formatter_chrono::_M_d_e)
>> > (__formatter_chrono::_M_H_I, __formatter_chrono::_M_m)
>> > (__formatter_chrono::_M_u_w, __formatter_chrono::_M_U_V_W): Remove
>> > __mod argument and call to _M_locale_fmt.
>> >---
>> > libstdc++-v3/include/bits/chrono_io.h | 340 +++++++++++++-------------
>> > 1 file changed, 172 insertions(+), 168 deletions(-)
>> >
>> >diff --git a/libstdc++-v3/include/bits/chrono_io.h
>> b/libstdc++-v3/include/bits/chrono_io.h
>> >index 35e95906e6a..d451bde722d 100644
>> >--- a/libstdc++-v3/include/bits/chrono_io.h
>> >+++ b/libstdc++-v3/include/bits/chrono_io.h
>> >@@ -906,6 +906,40 @@ namespace __format
>> > return __format::__write(std::move(__out), __s);
>> > }
>> >
>> >+ [[__gnu__::__always_inline__]]
>> >+ static bool
>> >+ _S_localized_spec(_CharT __conv, _CharT __mod)
>> >+ {
>> >+ switch (__conv)
>> >+ {
>> >+ case 'c':
>> >+ case 'r':
>> >+ case 'x':
>> >+ case 'X':
>> >+ return true;
>> >+ case 'z':
>> >+ return false;
>> >+ default:
>> >+ return (bool)__mod;
>> >+ };
>> >+ }
>> >+
>> >+ // Use the formatting locale's std::time_put facet to produce
>> >+ // a locale-specific representation.
>> >+ template<typename _Iter>
>> >+ _Iter
>> >+ _M_locale_fmt(_Iter __out, const locale& __loc, const struct tm&
>> __tm,
>> >+ char __fmt, char __mod) const
>> >+ {
>> >+ basic_ostringstream<_CharT> __os;
>> >+ __os.imbue(__loc);
>> >+ const auto& __tp = use_facet<time_put<_CharT>>(__loc);
>> >+ __tp.put(__os, __os, _S_space, &__tm, __fmt, __mod);
>> >+ if (__os)
>> >+ __out = _M_write(std::move(__out), __loc, __os.view());
>> >+ return __out;
>> >+ }
>> >+
>> > template<typename _Out, typename _FormatContext>
>> > _Out
>> > _M_format_to(const _ChronoData<_CharT>& __t, _Out __out,
>> >@@ -923,6 +957,36 @@ namespace __format
>> > return std::move(__out);
>> > };
>> >
>> >+ struct tm __tm{};
>> >+ bool __use_locale_fmt = false;
>> >+ if (_M_spec._M_localized && _M_spec._M_locale_specific)
>> >+ if (__fc.locale() != locale::classic())
>> >+ {
>> >+ __use_locale_fmt = true;
>> >+
>> >+ __tm.tm_year = (int)__t._M_year - 1900;
>> >+ __tm.tm_yday = __t._M_day_of_year.count();
>> >+ __tm.tm_mon = (unsigned)__t._M_month - 1;
>> >+ __tm.tm_mday = (unsigned)__t._M_day;
>> >+ __tm.tm_wday = __t._M_weekday.c_encoding();
>> >+ __tm.tm_hour = __t._M_hours.count();
>> >+ __tm.tm_min = __t._M_minutes.count();
>> >+ __tm.tm_sec = __t._M_seconds.count();
>> >+
>> >+ // Some locales use %Z in their %c format but we don't
>> want strftime
>> >+ // to use the system's local time zone (from
>> /etc/localtime or $TZ)
>> >+ // as the output for %Z. Setting tm_isdst to -1 says
>> there is no
>> >+ // time zone info available for the time in __tm.
>> >+ __tm.tm_isdst = -1;
>> >+
>> >+#ifdef _GLIBCXX_USE_STRUCT_TM_TM_ZONE
>> >+ // POSIX.1-2024 adds tm.tm_zone which will be used for %Z.
>> >+ // BSD has had tm_zone since 1987 but as char* so cast
>> away const.
>> >+ if (__t._M_zone_cstr)
>> >+ __tm.tm_zone = const_cast<char*>(__t._M_zone_cstr);
>> >+#endif
>> >+ }
>> >+
>> > // Characters to output for "%n", "%t" and "%%" specifiers.
>> > constexpr const _CharT* __literals = _GLIBCXX_WIDEN("\n\t%");
>> >
>> >@@ -932,7 +996,10 @@ namespace __format
>> > do
>> > {
>> > _CharT __c = *__first++;
>> >- switch (__c)
>> >+ if (__use_locale_fmt && _S_localized_spec(__c, __mod))
>> [[unlikely]]
>> >+ __out = _M_locale_fmt(std::move(__out), __fc.locale(),
>> >+ __tm, __c, __mod);
>> >+ else switch (__c)
>> > {
>> > // %\0 is extension for handling weekday index
>> > case '\0':
>> >@@ -948,22 +1015,20 @@ namespace __format
>> > __out = _M_b_B(__t._M_month, std::move(__out), __fc,
>> __c == 'B');
>> > break;
>> > case 'c':
>> >- case 'r':
>> >- case 'x':
>> >- case 'X':
>> >- __out = _M_c_r_x_X(__t, std::move(__out), __fc, __c,
>> __mod);
>> >+ __out = _M_c(__t, std::move(__out), __fc);
>> > break;
>> > case 'C':
>> > case 'y':
>> > case 'Y':
>> >- __out = _M_C_y_Y(__t._M_year, std::move(__out), __fc,
>> __c, __mod);
>> >+ __out = _M_C_y_Y(__t._M_year, std::move(__out), __fc,
>> __c);
>> > break;
>> > case 'd':
>> > case 'e':
>> >- __out = _M_d_e(__t._M_day, std::move(__out), __fc, __c,
>> __mod == 'O');
>> >+ __out = _M_d_e(__t._M_day, std::move(__out), __fc, __c);
>> > break;
>> > case 'D':
>> >- __out = _M_D(__t, std::move(__out), __fc);
>> >+ case 'x':
>> >+ __out = _M_D_x(__t, std::move(__out), __fc);
>> > break;
>> > case 'F':
>> > __out = _M_F(__t, std::move(__out), __fc);
>> >@@ -974,16 +1039,16 @@ namespace __format
>> > break;
>> > case 'H':
>> > case 'I':
>> >- __out = _M_H_I(__t._M_hours, __print_sign(), __fc, __c,
>> __mod == 'O');
>> >+ __out = _M_H_I(__t._M_hours, __print_sign(), __fc, __c);
>> > break;
>> > case 'j':
>> > __out = _M_j(__t, __print_sign(), __fc);
>> > break;
>> > case 'm':
>> >- __out = _M_m(__t._M_month, std::move(__out), __fc,
>> __mod == 'O');
>> >+ __out = _M_m(__t._M_month, std::move(__out), __fc);
>> > break;
>> > case 'M':
>> >- __out = _M_M(__t._M_minutes, __print_sign(), __fc,
>> __mod == 'O');
>> >+ __out = _M_M(__t._M_minutes, __print_sign(), __fc);
>> > break;
>> > case 'p':
>> > __out = _M_p(__t._M_hours, std::move(__out), __fc);
>> >@@ -994,22 +1059,28 @@ namespace __format
>> > case 'Q':
>> > __out = _M_Q(__t, __print_sign(), __fc);
>> > break;
>> >+ case 'r':
>> >+ __out = _M_r(__t, __print_sign(), __fc);
>> >+ break;
>> > case 'R':
>> >+ case 'X':
>> >+ __out = _M_R_X(__t, __print_sign(), __fc, __c != 'R');
>> >+ break;
>> > case 'T':
>> >- __out = _M_R_T(__t, __print_sign(), __fc, __c == 'T');
>> >+ __out = _M_T(__t, __print_sign(), __fc);
>> > break;
>> >+
>> > case 'S':
>> >- __out = _M_S(__t, __print_sign(), __fc, __mod == 'O');
>> >+ __out = _M_S(__t, __print_sign(), __fc, __mod != 'O');
>> > break;
>> > case 'u':
>> > case 'w':
>> >- __out = _M_u_w(__t._M_weekday, std::move(__out), __fc,
>> __c, __mod == 'O');
>> >+ __out = _M_u_w(__t._M_weekday, std::move(__out), __fc,
>> __c);
>> > break;
>> > case 'U':
>> > case 'V':
>> > case 'W':
>> >- __out = _M_U_V_W(__t, std::move(__out), __fc, __c,
>> >- __mod == 'O');
>> >+ __out = _M_U_V_W(__t, std::move(__out), __fc, __c);
>> > break;
>> > case 'z':
>> > __out = _M_z(__t._M_zone_offset, std::move(__out),
>> __fc, (bool)__mod);
>> >@@ -1132,50 +1203,27 @@ namespace __format
>> >
>> > template<typename _FormatContext>
>> > typename _FormatContext::iterator
>> >- _M_c_r_x_X(const _ChronoData<_CharT>& __t, typename
>> _FormatContext::iterator __out,
>> >- _FormatContext& __ctx, _CharT __conv, _CharT __mod)
>> const
>> >+ _M_c(const _ChronoData<_CharT>& __t, typename
>> _FormatContext::iterator __out,
>> >+ _FormatContext& __ctx) const
>> > {
>> >- // %c Locale's date and time representation.
>> >- // %Ec Locale's alternate date and time representation.
>> >- // %r Locale's 12-hour clock time.
>> >- // %x Locale's date rep
>> >- // %Ex Locale's alternative date representation.
>> >- // %X Locale's time rep
>> >- // %EX Locale's alternative time representation.
>> >-
>> >- using namespace chrono;
>> >- struct tm __tm{};
>> >-
>> >- // Some locales use %Z in their %c format but we don't want
>> strftime
>> >- // to use the system's local time zone (from /etc/localtime or
>> $TZ)
>> >- // as the output for %Z. Setting tm_isdst to -1 says there is no
>> >- // time zone info available for the time in __tm.
>> >- __tm.tm_isdst = -1;
>> >-
>> >-#ifdef _GLIBCXX_USE_STRUCT_TM_TM_ZONE
>> >- // POSIX.1-2024 adds tm.tm_zone which will be used for %Z.
>> >- // BSD has had tm_zone since 1987 but as char* so cast away
>> const.
>> >- if (__t._M_zone_cstr)
>> >- __tm.tm_zone = const_cast<char*>(__t._M_zone_cstr);
>> >-#endif
>> >-
>> >- __tm.tm_year = (int)__t._M_year - 1900;
>> >- __tm.tm_yday = __t._M_day_of_year.count();
>> >- __tm.tm_mon = (unsigned)__t._M_month - 1;
>> >- __tm.tm_mday = (unsigned)__t._M_day;
>> >- __tm.tm_wday = __t._M_weekday.c_encoding();
>> >- __tm.tm_hour = __t._M_hours.count();
>> >- __tm.tm_min = __t._M_minutes.count();
>> >- __tm.tm_sec = __t._M_seconds.count();
>> >-
>> >- return _M_locale_fmt(std::move(__out), _M_locale(__ctx), __tm,
>> >- __conv, __mod);
>> >+ // %c Locale's date and time representation, for C-locale: %a
>> %b %e %T %Y
>> >+ // %Ec Locale's alternate date and time representation, for
>> C-locale same as above
>> >+
>> >+ __out = _M_a_A(__t._M_weekday, std::move(__out), __ctx, false);
>> >+ *__out = _S_space;
>> >+ __out = _M_b_B(__t._M_month, std::move(++__out), __ctx, false);
>> >+ *__out = _S_space;
>> >+ __out = _M_d_e(__t._M_day, std::move(++__out), __ctx, 'e');
>> >+ *__out = _S_space;
>> >+ __out = _M_R_X(__t, std::move(++__out), __ctx, true);
>> >+ *__out = _S_space;
>> >+ return _M_C_y_Y(__t._M_year, std::move(__out), __ctx, 'Y');
>> > }
>> >
>> > template<typename _FormatContext>
>> > typename _FormatContext::iterator
>> > _M_C_y_Y(chrono::year __y, typename _FormatContext::iterator
>> __out,
>> >- _FormatContext& __ctx, _CharT __conv, _CharT __mod = 0)
>> const
>> >+ _FormatContext& __ctx, _CharT __conv) const
>> > {
>> > // %C Year divided by 100 using floored division.
>> > // %EC Locale's alternative preresentation of the century (era
>> name).
>> >@@ -1185,15 +1233,6 @@ namespace __format
>> > // %Y Year as a decimal number.
>> > // %EY Locale's alternative full year representation.
>> >
>> >- if (__mod && _M_spec._M_localized) [[unlikely]]
>> >- if (auto __loc = __ctx.locale(); __loc != locale::classic())
>> >- {
>> >- struct tm __tm{};
>> >- __tm.tm_year = (int)__y - 1900;
>> >- return _M_locale_fmt(std::move(__out), __loc, __tm,
>> >- __conv, __mod);
>> >- }
>> >-
>> > int __yi = (int)__y;
>> > const bool __is_neg = __yi < 0;
>> > __yi = __builtin_abs(__yi);
>> >@@ -1235,9 +1274,13 @@ namespace __format
>> >
>> > template<typename _FormatContext>
>> > typename _FormatContext::iterator
>> >- _M_D(const _ChronoData<_CharT>& __t, typename
>> _FormatContext::iterator __out,
>> >- _FormatContext&) const
>> >+ _M_D_x(const _ChronoData<_CharT>& __t, typename
>> _FormatContext::iterator __out,
>> >+ _FormatContext&) const
>> > {
>> >+ // %D Equivalent to %m/%d/%y
>> >+ // %x Locale's date rep, for C-locale: %m/%d/%y
>> >+ // %Ex Locale's alternative date representation, for C-locale
>> same as above
>> >+
>> > auto __di = (unsigned)__t._M_day;
>> > auto __mi = (unsigned)__t._M_month;
>> > auto __yi = __builtin_abs((int)__t._M_year) % 100;
>> >@@ -1267,7 +1310,7 @@ namespace __format
>> > template<typename _FormatContext>
>> > typename _FormatContext::iterator
>> > _M_d_e(chrono::day __d, typename _FormatContext::iterator __out,
>> >- _FormatContext& __ctx, _CharT __conv, bool __mod = false)
>> const
>> >+ _FormatContext& __ctx, _CharT __conv) const
>> > {
>> > // %d The day of month as a decimal number.
>> > // %Od Locale's alternative representation.
>> >@@ -1276,15 +1319,6 @@ namespace __format
>> >
>> > unsigned __i = (unsigned)__d;
>> >
>> >- if (__mod && _M_spec._M_localized) [[unlikely]]
>> >- if (auto __loc = __ctx.locale(); __loc != locale::classic())
>> >- {
>> >- struct tm __tm{};
>> >- __tm.tm_mday = __i;
>> >- return _M_locale_fmt(std::move(__out), __loc, __tm,
>> >- (char)__conv, 'O');
>> >- }
>> >-
>> > _CharT __buf[3];
>> > auto __sv = _S_str_d2(__buf, __i);
>> > if (__conv == _CharT('e') && __i < 10)
>> >@@ -1360,7 +1394,7 @@ namespace __format
>> > template<typename _FormatContext>
>> > typename _FormatContext::iterator
>> > _M_H_I(chrono::hours __h, typename _FormatContext::iterator __out,
>> >- _FormatContext& __ctx, _CharT __conv, bool __mod = false)
>> const
>> >+ _FormatContext& __ctx, _CharT __conv) const
>> > {
>> > // %H The hour (24-hour clock) as a decimal number.
>> > // %OH Locale's alternative representation.
>> >@@ -1369,15 +1403,6 @@ namespace __format
>> >
>> > int __i = __h.count();
>> >
>> >- if (__mod && _M_spec._M_localized) [[unlikely]]
>> >- if (auto __loc = __ctx.locale(); __loc != locale::classic())
>> >- {
>> >- struct tm __tm{};
>> >- __tm.tm_hour = __i;
>> >- return _M_locale_fmt(std::move(__out), __loc, __tm,
>> >- (char)__conv, 'O');
>> >- }
>> >-
>> > if (__conv == _CharT('I'))
>> > {
>> > __i %= 12;
>> >@@ -1409,22 +1434,13 @@ namespace __format
>> > template<typename _FormatContext>
>> > typename _FormatContext::iterator
>> > _M_m(chrono::month __m, typename _FormatContext::iterator __out,
>> >- _FormatContext& __ctx, bool __mod) const
>> >+ _FormatContext& __ctx) const
>> > {
>> > // %m month as a decimal number.
>> > // %Om Locale's alternative representation.
>> >
>> > auto __i = (unsigned)__m;
>> >
>> >- if (__mod && _M_spec._M_localized) [[unlikely]] // %Om
>> >- if (auto __loc = __ctx.locale(); __loc != locale::classic())
>> >- {
>> >- struct tm __tm{};
>> >- __tm.tm_mon = __i - 1;
>> >- return _M_locale_fmt(std::move(__out), __loc, __tm,
>> >- 'm', 'O');
>> >- }
>> >-
>> > _CharT __buf[3];
>> > return __format::__write(std::move(__out), _S_str_d2(__buf,
>> __i));
>> > }
>> >@@ -1432,22 +1448,12 @@ namespace __format
>> > template<typename _FormatContext>
>> > typename _FormatContext::iterator
>> > _M_M(chrono::minutes __m, typename _FormatContext::iterator __out,
>> >- _FormatContext& __ctx, bool __mod) const
>> >+ _FormatContext& __ctx) const
>> > {
>> > // %M The minute as a decimal number.
>> > // %OM Locale's alternative representation.
>> >
>> > auto __i = __m.count();
>> >-
>> >- if (__mod && _M_spec._M_localized) [[unlikely]] // %OM
>> >- if (auto __loc = __ctx.locale(); __loc != locale::classic())
>> >- {
>> >- struct tm __tm{};
>> >- __tm.tm_min = __i;
>> >- return _M_locale_fmt(std::move(__out), __loc, __tm,
>> >- 'M', 'O');
>> >- }
>> >-
>> > return __format::__write(std::move(__out), _S_two_digits(__i));
>> > }
>> >
>> >@@ -1488,17 +1494,42 @@ namespace __format
>> >
>> > template<typename _FormatContext>
>> > typename _FormatContext::iterator
>> >- _M_R_T(const _ChronoData<_CharT>& __t, typename
>> _FormatContext::iterator __out,
>> >+ _M_r(const _ChronoData<_CharT>& __t, typename
>> _FormatContext::iterator __out,
>> >+ _FormatContext& __ctx) const
>> >+ {
>> >+ // %r Locale's 12-hour clock time, for C-locale: %I:%M:%S %p
>> >+ auto __hi = __t._M_hours.count() % 12;
>> >+ if (__hi == 0)
>> >+ __hi = 12;
>> >+
>> >+ _CharT __buf[9];
>> >+ __buf[2] = _S_colon;
>> >+ __buf[5] = _S_colon;
>> >+ __buf[8] = _S_space;
>> >+ _S_fill_two_digits(__buf, __hi);
>> >+ _S_fill_two_digits(__buf + 3, __t._M_minutes.count());
>> >+ _S_fill_two_digits(__buf + 6, __t._M_seconds.count());
>> >+
>> >+ __string_view __sv(__buf, 9);
>> >+ __out = __format::__write(std::move(__out), __sv);
>> >+ return _M_p(__t._M_hours, std::move(__out), __ctx);
>> >+ }
>> >+
>> >+ template<typename _FormatContext>
>> >+ typename _FormatContext::iterator
>> >+ _M_R_X(const _ChronoData<_CharT>& __t, typename
>> _FormatContext::iterator __out,
>> > _FormatContext& __ctx, bool __secs) const
>> > {
>> >- // %R Equivalent to %H:%M
>> >- // %T Equivalent to %H:%M:%S
>> >+ // %R Equivalent to %H:%M
>> >+ // %X Locale's time rep, for C-locale: %H:%M:%S (without
>> subseconds)
>> >+ // %EX Locale's alternative time representation, for C-locale
>> same as above
>> >+
>> > auto __hi = __t._M_hours.count();
>> >
>> >- _CharT __buf[6];
>> >+ _CharT __buf[8];
>> > __buf[2] = _S_colon;
>> > __buf[5] = _S_colon;
>> >- __string_view __sv(__buf, 5 + __secs);
>> >+ __string_view __sv(__buf, 8);
>> >
>> > if (__hi >= 100) [[unlikely]]
>> > {
>> >@@ -1509,39 +1540,39 @@ namespace __format
>> > _S_fill_two_digits(__buf, __hi);
>> >
>> > _S_fill_two_digits(__buf + 3, __t._M_minutes.count());
>> >- __out = __format::__write(std::move(__out), __sv);
>> > if (__secs)
>> >- __out = _M_S(__t, std::move(__out), __ctx);
>> >- return __out;
>> >+ _S_fill_two_digits(__buf + 6, __t._M_seconds.count());
>> >+ else
>> >+ __sv.remove_suffix(3);
>> >+
>> >+ return __format::__write(std::move(__out), __sv);
>> > }
>> >
>> > template<typename _FormatContext>
>> > typename _FormatContext::iterator
>> > _M_S(const _ChronoData<_CharT>& __t, typename
>> _FormatContext::iterator __out,
>> >- _FormatContext& __ctx, bool __mod = false) const
>> >+ _FormatContext& __ctx, bool __subs = true) const
>> > {
>> >- // %S Seconds as a decimal number.
>>
>> Doesn't this function still handle %S formats? Should this comment be
>> kept?
>>
> Yes, it gets called to handle '%S' in the big switch. It is no longer
> called by _M_T, which calls _M_subsecs
> directly.
>
Ah, you are referring to 'OS'. Yes, it is still-handled here, if the format
is not localized, or the locale is the same
as classic. The effect is that we do not print subseconds.
>
>> Apart from that, this patch looks great - OK for trunk (after the
>> _ChronoData one, obviously).
>>
>>
>> > // %OS The locale's alternative representation.
>> > auto __s = __t._M_seconds;
>> >
>> >- if (__mod && _M_spec._M_localized) [[unlikely]] // %OS
>> >- if (auto __loc = __ctx.locale(); __loc != locale::classic())
>> >- {
>> >- struct tm __tm{};
>> >- __tm.tm_sec = (int)__s.count();
>> >- return _M_locale_fmt(std::move(__out), __loc, __tm,
>> >- 'S', 'O');
>> >- }
>> >-
>> > __out = __format::__write(std::move(__out),
>> >- _S_two_digits(__s.count()));
>> >+ _S_two_digits(__s.count()));
>> >+ if (__subs)
>> >+ __out = _M_subsecs(__t, std::move(__out), __ctx);
>> >+ return __out;
>> >+ }
>> >
>> >+ template<typename _FormatContext>
>> >+ typename _FormatContext::iterator
>> >+ _M_subsecs(const _ChronoData<_CharT>& __t,
>> >+ typename _FormatContext::iterator __out,
>> >+ _FormatContext& __ctx) const
>> >+ {
>> > unsigned __prec = _M_spec._M_prec_kind != _WP_none
>> > ? _M_spec._M_get_precision(__ctx)
>> > : _M_spec._M_prec;
>> >-
>> >- // %OS formats don't include subseconds
>> >- if (__prec == 0 || __mod)
>> >+ if (__prec == 0)
>> > return __out;
>> >
>> > _CharT __dot = _S_dot;
>> >@@ -1595,25 +1626,25 @@ namespace __format
>> >
>> > // %t handled in _M_format
>> >
>> >+ template<typename _FormatContext>
>> >+ typename _FormatContext::iterator
>> >+ _M_T(const _ChronoData<_CharT>& __t, typename
>> _FormatContext::iterator __out,
>> >+ _FormatContext& __ctx) const
>> >+ {
>> >+ // %T Equivalent to %H:%M:%S, with subseconds
>> >+ __out = _M_R_X(__t, std::move(__out), __ctx, true);
>> >+ return _M_subsecs(__t, std::move(__out), __ctx);
>> >+ }
>> >+
>> > template<typename _FormatContext>
>> > typename _FormatContext::iterator
>> > _M_u_w(chrono::weekday __wd, typename _FormatContext::iterator
>> __out,
>> >- _FormatContext& __ctx, _CharT __conv, bool __mod = false)
>> const
>> >+ _FormatContext& __ctx, _CharT __conv) const
>> > {
>> > // %u ISO weekday as a decimal number (1-7), where Monday is 1.
>> > // %Ou Locale's alternative numeric rep.
>> > // %w Weekday as a decimal number (0-6), where Sunday is 0.
>> > // %Ow Locale's alternative numeric rep.
>> >-
>> >- if (__mod && _M_spec._M_localized) [[unlikely]]
>> >- if (auto __loc = __ctx.locale(); __loc != locale::classic())
>> >- {
>> >- struct tm __tm{};
>> >- __tm.tm_wday = __wd.c_encoding();
>> >- return _M_locale_fmt(std::move(__out), __loc, __tm,
>> >- (char)__conv, 'O');
>> >- }
>> >-
>> > unsigned __wdi = __conv == 'u' ? __wd.iso_encoding()
>> > : __wd.c_encoding();
>> > _CharT __buf[3];
>> >@@ -1623,7 +1654,7 @@ namespace __format
>> > template<typename _FormatContext>
>> > typename _FormatContext::iterator
>> > _M_U_V_W(const _ChronoData<_CharT>& __t, typename
>> _FormatContext::iterator __out,
>> >- _FormatContext& __ctx, _CharT __conv, bool __mod =
>> false) const
>> >+ _FormatContext& __ctx, _CharT __conv) const
>> > {
>> > // %U Week number of the year as a decimal number, from first
>> Sunday.
>> > // %OU Locale's alternative numeric rep.
>> >@@ -1633,17 +1664,6 @@ namespace __format
>> > // %OW Locale's alternative numeric rep.
>> > using namespace chrono;
>> >
>> >- if (__mod && _M_spec._M_localized) [[unlikely]]
>> >- if (auto __loc = __ctx.locale(); __loc != locale::classic())
>> >- {
>> >- struct tm __tm{};
>> >- __tm.tm_year = (int)__t._M_year - 1900;
>> >- __tm.tm_yday = __t._M_day_of_year.count();
>> >- __tm.tm_wday = __t._M_weekday.c_encoding();
>> >- return _M_locale_fmt(std::move(__out), __loc, __tm,
>> >- (char)__conv, 'O');
>> >- }
>> >-
>> > auto __d = __t._M_ldays;
>> > local_days __first; // First day of week 1.
>> > if (__conv == 'V') // W01 begins on Monday before first
>> Thursday.
>> >@@ -1755,22 +1775,6 @@ namespace __format
>> > __buf[2] = _S_chars[__n % 10];
>> > return __string_view(__buf.data(), 3);
>> > }
>> >-
>> >- // Use the formatting locale's std::time_put facet to produce
>> >- // a locale-specific representation.
>> >- template<typename _Iter>
>> >- _Iter
>> >- _M_locale_fmt(_Iter __out, const locale& __loc, const struct tm&
>> __tm,
>> >- char __fmt, char __mod) const
>> >- {
>> >- basic_ostringstream<_CharT> __os;
>> >- __os.imbue(__loc);
>> >- const auto& __tp = use_facet<time_put<_CharT>>(__loc);
>> >- __tp.put(__os, __os, _S_space, &__tm, __fmt, __mod);
>> >- if (__os)
>> >- __out = _M_write(std::move(__out), __loc, __os.view());
>> >- return __out;
>> >- }
>> > };
>> >
>> > template<typename _CharT>
>> >--
>> >2.49.0
>> >
>> >
>>
>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://gcc.gnu.org/pipermail/libstdc++/attachments/20250626/01729d3c/attachment-0001.htm>
More information about the Libstdc++
mailing list