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. 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 > >