[PATCH] libstdc++: Format chrono %a/%A/%b/%B/%p using locale's time_put [PR117214]
Tomasz Kaminski
tkaminsk@redhat.com
Wed Jul 2 09:29:10 GMT 2025
On Wed, Jul 2, 2025 at 9:13 AM XU Kailiang <xu2k3l4@outlook.com> wrote:
>
> C++ formatting locale could have a custom time_put that performs
> differently from the C locale, so do not use __timepunct directly.
>
> libstdc++-v3/ChangeLog:
>
> PR libstdc++/117214
> * include/bits/chrono_io.h (__formatter_chrono::_M_a_A,
> __formatter_chrono::_M_b_B, __formatter_chrono::_M_p): use
> _M_locale_fmt to format %a/%A/%b/%B/%p.
> * testsuite/std/time/format/pr117214_custom_timeput.cc: New
> test.
>
> Signed-off-by: XU Kailiang <xu2k3l4@outlook.com>
> ---
> libstdc++-v3/include/bits/chrono_io.h | 31 ++++++----------
> .../time/format/pr117214_custom_timeput.cc | 36 +++++++++++++++++++
> 2 files changed, 47 insertions(+), 20 deletions(-)
> create mode 100644
> libstdc++-v3/testsuite/std/time/format/pr117214_custom_timeput.cc
>
> diff --git a/libstdc++-v3/include/bits/chrono_io.h
> b/libstdc++-v3/include/bits/chrono_io.h
> index abbf4efcc3b..8358105c26b 100644
> --- a/libstdc++-v3/include/bits/chrono_io.h
> +++ b/libstdc++-v3/include/bits/chrono_io.h
> @@ -905,14 +905,10 @@ namespace __format
> }
>
> locale __loc = _M_locale(__ctx);
> - const auto& __tp = use_facet<__timepunct<_CharT>>(__loc);
> - const _CharT* __days[7];
> - if (__full)
> - __tp._M_days(__days);
> - else
> - __tp._M_days_abbreviated(__days);
> - __string_view __str(__days[__wd.c_encoding()]);
> - return _M_write(std::move(__out), __loc, __str);
> + struct tm __tm{};
> + __tm.tm_wday = __wd.c_encoding();
> + return _M_locale_fmt(std::move(__out), __loc, __tm,
> + __full ? 'A' : 'a', 0);
>
I have recently removed all call to _M_locale_fmt from inside the
specifiers,
into the format loop, instead of calling it per each specifier individually.
I think, we should follow same approach here, by updating _S_localized_spec
to
return true for all above specifiers.
Then we can remove calls to _M_write and replace it with __format_writes, as
this functions will be only used for C locale.
> }
>
> template<typename _Tp, typename _FormatContext>
> @@ -936,14 +932,10 @@ namespace __format
> }
>
> locale __loc = _M_locale(__ctx);
> - const auto& __tp = use_facet<__timepunct<_CharT>>(__loc);
> - const _CharT* __months[12];
> - if (__full)
> - __tp._M_months(__months);
> - else
> - __tp._M_months_abbreviated(__months);
> - __string_view __str(__months[(unsigned)__m - 1]);
> - return _M_write(std::move(__out), __loc, __str);
> + struct tm __tm{};
> + __tm.tm_mon = (unsigned)__m - 1;
> + return _M_locale_fmt(std::move(__out), __loc, __tm,
> + __full ? 'B' : 'b', 0);
> }
>
> template<typename _Tp, typename _FormatContext>
> @@ -1329,10 +1321,9 @@ namespace __format
> __hi %= 24;
>
> locale __loc = _M_locale(__ctx);
> - const auto& __tp = use_facet<__timepunct<_CharT>>(__loc);
> - const _CharT* __ampm[2];
> - __tp._M_am_pm(__ampm);
> - return _M_write(std::move(__out), __loc, __ampm[__hi >= 12]);
> + struct tm __tm{};
> + __tm.tm_hour = __hi;
> + return _M_locale_fmt(std::move(__out), __loc, __tm, 'p', 0);
> }
>
> template<typename _Tp, typename _FormatContext>
> diff --git
> a/libstdc++-v3/testsuite/std/time/format/pr117214_custom_timeput.cc
> b/libstdc++-v3/testsuite/std/time/format/pr117214_custom_timeput.cc
> new file mode 100644
> index 00000000000..8c9f3d29bc6
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/std/time/format/pr117214_custom_timeput.cc
> @@ -0,0 +1,36 @@
> +// { dg-do run { target c++20 } }
> +
> +#include <chrono>
> +#include <format>
> +#include <locale>
> +#include <testsuite_hooks.h>
> +
> +struct custom_time_put : 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
> + {
> + using Base = std::time_put<char>;
> +
> + switch (format) {
> + case 'a': case 'A': case 'b': case 'B': case 'p':
> + *out++ = '[';
> + *out++ = format;
> + *out++ = ']';
> + }
> + return Base::do_put(out, io, fill, t, format, modifier);
> + }
> +};
> +
> +int main()
> +{
> + using namespace std::chrono;
> + std::locale loc(std::locale::classic(), new custom_time_put);
> +#define test(t, fmt, exp) VERIFY( std::format(loc, fmt, t) == exp )
> + test(Monday, "{:L%a}", "[a]Mon");
> + test(Monday, "{:L%A}", "[A]Monday");
> + test(January, "{:L%b}", "[b]Jan");
> + test(January, "{:L%B}", "[B]January");
> + test(1h, "{:L%p}", "[p]AM");
> +}
> --
> 2.50.0
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://gcc.gnu.org/pipermail/libstdc++/attachments/20250702/b7ea3f68/attachment.htm>
More information about the Libstdc++
mailing list