On Wed, 2 Jul 2025 at 10:30, Tomasz Kaminski <tkami...@redhat.com> wrote: > > > > On Wed, Jul 2, 2025 at 9:13 AM XU Kailiang <xu2k...@outlook.com> wrote: >> >> >> C++ formatting locale could have a custom time_put that performs >> differently from the C locale, so do not use __timepunct directly. >> >> libstdc++-v3/ChangeLog: >> >> PR libstdc++/117214 >> * include/bits/chrono_io.h (__formatter_chrono::_M_a_A, >> __formatter_chrono::_M_b_B, __formatter_chrono::_M_p): use >> _M_locale_fmt to format %a/%A/%b/%B/%p. >> * testsuite/std/time/format/pr117214_custom_timeput.cc: New >> test. >> >> Signed-off-by: XU Kailiang <xu2k...@outlook.com> >> --- >> libstdc++-v3/include/bits/chrono_io.h | 31 ++++++---------- >> .../time/format/pr117214_custom_timeput.cc | 36 +++++++++++++++++++ >> 2 files changed, 47 insertions(+), 20 deletions(-) >> create mode 100644 >> libstdc++-v3/testsuite/std/time/format/pr117214_custom_timeput.cc >> >> diff --git a/libstdc++-v3/include/bits/chrono_io.h >> b/libstdc++-v3/include/bits/chrono_io.h >> index abbf4efcc3b..8358105c26b 100644 >> --- a/libstdc++-v3/include/bits/chrono_io.h >> +++ b/libstdc++-v3/include/bits/chrono_io.h >> @@ -905,14 +905,10 @@ namespace __format >> } >> >> locale __loc = _M_locale(__ctx); >> - const auto& __tp = use_facet<__timepunct<_CharT>>(__loc); >> - const _CharT* __days[7]; >> - if (__full) >> - __tp._M_days(__days); >> - else >> - __tp._M_days_abbreviated(__days); >> - __string_view __str(__days[__wd.c_encoding()]); >> - return _M_write(std::move(__out), __loc, __str); >> + struct tm __tm{}; >> + __tm.tm_wday = __wd.c_encoding(); >> + return _M_locale_fmt(std::move(__out), __loc, __tm, >> + __full ? 'A' : 'a', 0); > > I have recently removed all call to _M_locale_fmt from inside the specifiers, > into the format loop, instead of calling it per each specifier individually. > I think, we should follow same approach here, by updating _S_localized_spec to > return true for all above specifiers.
Yes please. > Then we can remove calls to _M_write and replace it with __format_writes, as > this functions will be only used for C locale. >> >> } >> >> template<typename _Tp, typename _FormatContext> >> @@ -936,14 +932,10 @@ namespace __format >> } >> >> locale __loc = _M_locale(__ctx); >> - const auto& __tp = use_facet<__timepunct<_CharT>>(__loc); >> - const _CharT* __months[12]; >> - if (__full) >> - __tp._M_months(__months); >> - else >> - __tp._M_months_abbreviated(__months); >> - __string_view __str(__months[(unsigned)__m - 1]); >> - return _M_write(std::move(__out), __loc, __str); >> + struct tm __tm{}; >> + __tm.tm_mon = (unsigned)__m - 1; >> + return _M_locale_fmt(std::move(__out), __loc, __tm, >> + __full ? 'B' : 'b', 0); >> } >> >> template<typename _Tp, typename _FormatContext> >> @@ -1329,10 +1321,9 @@ namespace __format >> __hi %= 24; >> >> locale __loc = _M_locale(__ctx); >> - const auto& __tp = use_facet<__timepunct<_CharT>>(__loc); >> - const _CharT* __ampm[2]; >> - __tp._M_am_pm(__ampm); >> - return _M_write(std::move(__out), __loc, __ampm[__hi >= 12]); >> + struct tm __tm{}; >> + __tm.tm_hour = __hi; >> + return _M_locale_fmt(std::move(__out), __loc, __tm, 'p', 0); >> } >> >> template<typename _Tp, typename _FormatContext> >> diff --git >> a/libstdc++-v3/testsuite/std/time/format/pr117214_custom_timeput.cc >> b/libstdc++-v3/testsuite/std/time/format/pr117214_custom_timeput.cc >> new file mode 100644 >> index 00000000000..8c9f3d29bc6 >> --- /dev/null >> +++ b/libstdc++-v3/testsuite/std/time/format/pr117214_custom_timeput.cc >> @@ -0,0 +1,36 @@ >> +// { dg-do run { target c++20 } } >> + >> +#include <chrono> >> +#include <format> >> +#include <locale> >> +#include <testsuite_hooks.h> >> + >> +struct custom_time_put : std::time_put<char> >> +{ >> + iter_type >> + do_put(iter_type out, std::ios_base& io, char_type fill, const tm* t, >> + char format, char modifier) const override >> + { >> + using Base = std::time_put<char>; >> + >> + switch (format) { >> + case 'a': case 'A': case 'b': case 'B': case 'p': >> + *out++ = '['; >> + *out++ = format; >> + *out++ = ']'; >> + } >> + return Base::do_put(out, io, fill, t, format, modifier); >> + } >> +}; >> + >> +int main() >> +{ >> + using namespace std::chrono; >> + std::locale loc(std::locale::classic(), new custom_time_put); >> +#define test(t, fmt, exp) VERIFY( std::format(loc, fmt, t) == exp ) >> + test(Monday, "{:L%a}", "[a]Mon"); >> + test(Monday, "{:L%A}", "[A]Monday"); >> + test(January, "{:L%b}", "[b]Jan"); >> + test(January, "{:L%B}", "[B]January"); >> + test(1h, "{:L%p}", "[p]AM"); >> +} >> -- >> 2.50.0 >>