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); } 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