[PATCH v2 1/3] libstdc++: Use formatting locale for std::time_put formats
Jonathan Wakely
jwakely@redhat.com
Thu Mar 20 16:20:43 GMT 2025
On Thu, 20 Mar 2025 at 16:16, Jonathan Wakely <jwakely@redhat.com> wrote:
>
> When using std::time_put to format a chrono value, we should imbue the
> formatting locale into the stream. This ensures that when
> std::time_put::do_put uses a ctype or __timepunct facet from the locale,
> it gets the correct facets.
>
> libstdc++-v3/ChangeLog:
>
> * include/bits/chrono_io.h (__formatter_chrono::_M_locale_fmt):
> Imbue locale into ostringstream.
> * testsuite/std/time/format/localized.cc: Check that correct
> locale is used for call to time_put::put.
> ---
>
> Now with a test that shows the bug independent of the PR117214 patches
> to use std::time_put for %c formats.
>
> Tested x86_64-linux.
>
> libstdc++-v3/include/bits/chrono_io.h | 1 +
> .../testsuite/std/time/format/localized.cc | 30 +++++++++++++++++++
> 2 files changed, 31 insertions(+)
>
> diff --git a/libstdc++-v3/include/bits/chrono_io.h b/libstdc++-v3/include/bits/chrono_io.h
> index c16b555df29..55ebd4ee061 100644
> --- a/libstdc++-v3/include/bits/chrono_io.h
> +++ b/libstdc++-v3/include/bits/chrono_io.h
> @@ -1697,6 +1697,7 @@ namespace __format
> char __fmt, char __mod) const
> {
> basic_ostringstream<_CharT> __os;
> + __os.imbue(__loc);
> const auto& __tp = use_facet<time_put<_CharT>>(__loc);
> __tp.put(__os, __os, _S_space, &__tm, __fmt, __mod);
> if (__os)
> diff --git a/libstdc++-v3/testsuite/std/time/format/localized.cc b/libstdc++-v3/testsuite/std/time/format/localized.cc
> index 393d0d200e4..437a4a011b2 100644
> --- a/libstdc++-v3/testsuite/std/time/format/localized.cc
> +++ b/libstdc++-v3/testsuite/std/time/format/localized.cc
> @@ -13,6 +13,7 @@
>
> #include <chrono>
> #include <format>
> +#include <locale>
> #include <stdio.h>
> #include <testsuite_hooks.h>
>
> @@ -81,6 +82,35 @@ test_en()
> }
> }
>
> +void
> +test_locale_imbued()
> +{
> + // Custom time_put facet which returns %b string for %Om
> + struct TimePut : 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
> + {
> + if (format == 'm' && modifier == 'O')
> + format = 'b';
> + return std::time_put<char>::do_put(out, io, fill, t, format, 0);
> + }
> + };
> +
> + auto m = std::chrono::March;
> +
> + std::locale fr(ISO_8859(1,fr_FR));
> + std::locale fr2(fr, new TimePut);
> + auto s1 = std::format(fr2, "{:L%Om}", m);
> + VERIFY( s1 == std::format(fr, "{:L}", m) );
> +
> + std::locale es(ISO_8859(1,es_ES));
> + std::locale es2(es, new TimePut);
> + auto s2 = std::format(es2, "{:L%Om}", m);
> + VERIFY( s2 == std::format(es, "{:L}", m) );
> +}
> +
> int main()
> {
> test_ru();
It would help if I added the new test_locale_imbued() function to main
so that it actually runs.
Luckily it passes when I do that.
More information about the Libstdc++
mailing list