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(); -- 2.49.0