[PATCH 2/3] libstdc++: Fix localized D_T_FMT %c formatting for <chrono> [PR117214]
Tomasz Kaminski
tkaminsk@redhat.com
Fri Mar 21 10:51:15 GMT 2025
On Thu, Mar 20, 2025 at 10:31 AM Jonathan Wakely <jwakely@redhat.com> wrote:
> From: XU Kailiang <xu2k3l4@outlook.com>
>
> 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>
> ---
>
> Tested x86_64-linux.
>
LGTM
>
> libstdc++-v3/include/bits/chrono_io.h | 35 ++++++++++---------
> .../testsuite/std/time/format/pr117214.cc | 34 ++++++++++++++++++
> 2 files changed, 53 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 55ebd4ee061..86338d48d18 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 00000000000..e7831832206
> --- /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();
> +}
> --
> 2.48.1
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://gcc.gnu.org/pipermail/libstdc++/attachments/20250321/0d325433/attachment.htm>
More information about the Libstdc++
mailing list