diff options
author | XU Kailiang <xu2k3l4@outlook.com> | 2025-03-01 13:23:21 +0800 |
---|---|---|
committer | Jonathan Wakely <redi@gcc.gnu.org> | 2025-03-21 10:28:15 +0000 |
commit | c24a1d58bc02daabafd5c94fca0984b70db811c8 (patch) | |
tree | b7e30df22cc4445af8b0f5a41ab8854138b148e5 | |
parent | 3c7f2fd8c4b330029c935f2785a5da9395355d7d (diff) | |
download | gcc-c24a1d58bc02daabafd5c94fca0984b70db811c8.zip gcc-c24a1d58bc02daabafd5c94fca0984b70db811c8.tar.gz gcc-c24a1d58bc02daabafd5c94fca0984b70db811c8.tar.bz2 |
libstdc++: Fix localized D_T_FMT %c formatting for <chrono> [PR117214]
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 contains strftime specifiers
which are not valid for chrono-specs, e.g. %l. 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 <xu2k3l4@outlook.com>
Co-authored-by: Jonathan Wakely <jwakely@redhat.com>
-rw-r--r-- | libstdc++-v3/include/bits/chrono_io.h | 35 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/std/time/format/pr117214.cc | 34 |
2 files changed, 53 insertions, 16 deletions
diff --git a/libstdc++-v3/include/bits/chrono_io.h b/libstdc++-v3/include/bits/chrono_io.h index 55ebd4e..86338d4 100644 --- a/libstdc++-v3/include/bits/chrono_io.h +++ b/libstdc++-v3/include/bits/chrono_io.h @@ -887,27 +887,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); // Either sys_days or local_days. + using _TDays = decltype(__d); + const year_month_day __ymd(__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)__ymd.month() - 1; + __tm.tm_mday = (unsigned)__ymd.day(); + __tm.tm_wday = weekday(__d).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 0000000..e783183 --- /dev/null +++ b/libstdc++-v3/testsuite/std/time/format/pr117214.cc @@ -0,0 +1,34 @@ +// { 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", + }; + std::chrono::sys_seconds t{std::chrono::seconds{1}}; + + for (auto locale_name : test_locales) + { + auto s = std::format(std::locale(locale_name), "{:L%c}", t); + VERIFY( !s.empty() ); + } +} + +int main() +{ + test_c(); +} |