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>
This commit is contained in:
parent
3c7f2fd8c4
commit
c24a1d58bc
2 changed files with 53 additions and 16 deletions
|
@ -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>
|
||||
|
|
34
libstdc++-v3/testsuite/std/time/format/pr117214.cc
Normal file
34
libstdc++-v3/testsuite/std/time/format/pr117214.cc
Normal file
|
@ -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();
|
||||
}
|
Loading…
Add table
Reference in a new issue