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

Reply via email to