Formatting a time point with %c was implemented by calling
std::vprint_to with format string constructed from locale's D_T_FMT
string, but in some locales this string does not compliant to
chrono-specs. So just use _M_locale_fmt to avoid this problem.
libstdc++-v3/ChangeLog:
PR libstdc++/117214
* include/bits/chrono_io.h (__formatter_chrono::_M_c): use
_M_locale_fmt to format %c time point.
* testsuite/std/time/format/pr117214.cc: New test.
Signed-off-by: XU Kailiang <[email protected]>
---
libstdc++-v3/include/bits/chrono_io.h | 35 ++++++++++---------
.../testsuite/std/time/format/pr117214.cc | 32 +++++++++++++++++
2 files changed, 51 insertions(+), 16 deletions(-)
create mode 100644 libstdc++-v3/testsuite/std/time/format/pr117214.cc
diff --git a/libstdc++-v3/include/bits/chrono_io.h b/libstdc++-
v3/include/bits/chrono_io.h
index 6c813bf439d..9a4fa153a98 100644
--- a/libstdc++-v3/include/bits/chrono_io.h
+++ b/libstdc++-v3/include/bits/chrono_io.h
@@ -787,27 +787,30 @@ namespace __format
template<typename _Tp, typename _FormatContext>
typename _FormatContext::iterator
- _M_c(const _Tp& __tt, typename _FormatContext::iterator __out,
+ _M_c(const _Tp& __t, typename _FormatContext::iterator __out,
_FormatContext& __ctx, bool __mod = false) const
{
// %c Locale's date and time representation.
// %Ec Locale's alternate date and time representation.
- basic_string<_CharT> __fmt;
- auto __t = _S_floor_seconds(__tt);
- locale __loc = _M_locale(__ctx);
- const auto& __tp = use_facet<__timepunct<_CharT>>(__loc);
- const _CharT* __formats[2];
- __tp._M_date_time_formats(__formats);
- if (*__formats[__mod]) [[likely]]
- {
- __fmt = _GLIBCXX_WIDEN("{:L}");
- __fmt.insert(3u, __formats[__mod]);
- }
- else
- __fmt = _GLIBCXX_WIDEN("{:L%a %b %e %T %Y}");
- return std::vformat_to(std::move(__out), __loc, __fmt,
-
std::make_format_args<_FormatContext>(__t));
+ using namespace chrono;
+ auto __d = _S_days(__t);
+ using _TDays = decltype(__d);
+ const auto __ymd = _S_date(__d);
+ const auto __y = __ymd.year();
+ const auto __hms = _S_hms(__t);
+
+ struct tm __tm{};
+ __tm.tm_year = (int)__y - 1900;
+ __tm.tm_yday = (__d - _TDays(__y/January/1)).count();
+ __tm.tm_mon = (unsigned)_S_month(__t) - 1;
+ __tm.tm_mday = (unsigned)_S_day(__t);
+ __tm.tm_wday = _S_weekday(__t).c_encoding();
+ __tm.tm_hour = __hms.hours().count();
+ __tm.tm_min = __hms.minutes().count();
+ __tm.tm_sec = __hms.seconds().count();
+ return _M_locale_fmt(std::move(__out), _M_locale(__ctx),
__tm, 'c',
+ __mod ? 'E' : '\0');
}
template<typename _Tp, typename _FormatContext>
diff --git a/libstdc++-v3/testsuite/std/time/format/pr117214.cc
b/libstdc++-v3/testsuite/std/time/format/pr117214.cc
new file mode 100644
index 00000000000..5b36edadfa0
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/time/format/pr117214.cc
@@ -0,0 +1,32 @@
+// { dg-do run { target c++20 } }
+// { dg-require-namedlocale "aa_DJ.UTF-8" }
+// { dg-require-namedlocale "ar_SA.UTF-8" }
+// { dg-require-namedlocale "ca_AD.UTF-8" }
+// { dg-require-namedlocale "az_IR.UTF-8" }
+// { dg-require-namedlocale "my_MM.UTF-8" }
+
+#include <chrono>
+#include <locale>
+#include <testsuite_hooks.h>
+
+void
+test_c()
+{
+ const char *test_locales[] = {
+ "aa_DJ.UTF-8",
+ "ar_SA.UTF-8",
+ "ca_AD.UTF-8",
+ "az_IR.UTF-8",
+ "my_MM.UTF-8",
+ };
+ for (auto locale_name : test_locales)
+ {
+ std::locale::global(std::locale(locale_name));
+ VERIFY( !std::format("{:L%c}", std::chrono::sys_seconds()).empty()
);
+ }
+}
+
+int main()
+{
+ test_c();
+}