[libcxx-commits] [libcxx] [libc++][chrono] Improves date formatting. (PR #86127)
Mark de Wever via libcxx-commits
libcxx-commits at lists.llvm.org
Tue Apr 16 23:09:39 PDT 2024
https://github.com/mordante updated https://github.com/llvm/llvm-project/pull/86127
>From 96fbdc08537d716635c50334dfa26e128a2a5c28 Mon Sep 17 00:00:00 2001
From: Mark de Wever <koraq at xs4all.nl>
Date: Thu, 21 Mar 2024 15:22:13 +0100
Subject: [PATCH] [libc++][chrono] Improves date formatting.
The formatting of years has been done manually since the results of %Y
outside the "typical" range may produce unexpected values. The same
applies to %F which is identical to %Y-%m-%d. Note of these conversion
specifiers is affected by the locale used. So it's trivial to manually
handle this case.
This removes several platform specific ifdefs from the tests.
---
libcxx/include/__chrono/formatter.h | 16 ++++-----
.../time.cal.ymd.nonmembers/ostream.pass.cpp | 34 -------------------
.../sys_date.ostream.pass.cpp | 34 -------------------
.../formatter.year_month_day.pass.cpp | 24 -------------
4 files changed, 7 insertions(+), 101 deletions(-)
diff --git a/libcxx/include/__chrono/formatter.h b/libcxx/include/__chrono/formatter.h
index d932a99f4b9983..f76e7b2ea0e864 100644
--- a/libcxx/include/__chrono/formatter.h
+++ b/libcxx/include/__chrono/formatter.h
@@ -322,15 +322,13 @@ _LIBCPP_HIDE_FROM_ABI void __format_chrono_using_chrono_specs(
__formatter::__format_year(__sstr, __t.tm_year + 1900);
break;
- case _CharT('F'): {
- int __year = __t.tm_year + 1900;
- if (__year < 1000) {
- __formatter::__format_year(__sstr, __year);
- __sstr << std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "-{:02}-{:02}"), __t.tm_mon + 1, __t.tm_mday);
- } else
- __facet.put(
- {__sstr}, __sstr, _CharT(' '), std::addressof(__t), std::to_address(__s), std::to_address(__it + 1));
- } break;
+ case _CharT('F'):
+ // Depending on the platform's libc the range of supported years is
+ // limited. Instead of testing all conditions use the internal
+ // implementation unconditionally.
+ __formatter::__format_year(__sstr, __t.tm_year + 1900);
+ __sstr << std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "-{:02}-{:02}"), __t.tm_mon + 1, __t.tm_mday);
+ break;
case _CharT('z'):
__formatter::__format_zone_offset(__sstr, __z.__offset, false);
diff --git a/libcxx/test/std/time/time.cal/time.cal.ymd/time.cal.ymd.nonmembers/ostream.pass.cpp b/libcxx/test/std/time/time.cal/time.cal.ymd/time.cal.ymd.nonmembers/ostream.pass.cpp
index ffc737fcad5dd2..20ffb165558e31 100644
--- a/libcxx/test/std/time/time.cal/time.cal.ymd/time.cal.ymd.nonmembers/ostream.pass.cpp
+++ b/libcxx/test/std/time/time.cal/time.cal.ymd/time.cal.ymd.nonmembers/ostream.pass.cpp
@@ -13,9 +13,6 @@
// TODO FMT This test should not require std::to_chars(floating-point)
// XFAIL: availability-fp_to_chars-missing
-// TODO FMT Investigate Windows issues.
-// XFAIL: msvc
-
// REQUIRES: locale.fr_FR.UTF-8
// REQUIRES: locale.ja_JP.UTF-8
@@ -89,20 +86,9 @@ static void test() {
TEST_EQUAL(stream_c_locale<CharT>(
std::chrono::year_month_day{std::chrono::year{2000}, std::chrono::month{2}, std::chrono::day{29}}),
SV("2000-02-29"));
-
-#if defined(_AIX)
- TEST_EQUAL(stream_c_locale<CharT>(
- std::chrono::year_month_day{std::chrono::year{32'767}, std::chrono::month{12}, std::chrono::day{31}}),
- SV("+32767-12-31"));
-#elif defined(_WIN32) // defined(_AIX)
- TEST_EQUAL(stream_c_locale<CharT>(
- std::chrono::year_month_day{std::chrono::year{32'767}, std::chrono::month{12}, std::chrono::day{31}}),
- SV(""));
-#else // defined(_AIX)
TEST_EQUAL(stream_c_locale<CharT>(
std::chrono::year_month_day{std::chrono::year{32'767}, std::chrono::month{12}, std::chrono::day{31}}),
SV("32767-12-31"));
-#endif // defined(_AIX)
TEST_EQUAL(stream_fr_FR_locale<CharT>(
std::chrono::year_month_day{std::chrono::year{-32'768}, std::chrono::month{1}, std::chrono::day{1}}),
@@ -122,19 +108,9 @@ static void test() {
TEST_EQUAL(stream_fr_FR_locale<CharT>(
std::chrono::year_month_day{std::chrono::year{2000}, std::chrono::month{2}, std::chrono::day{29}}),
SV("2000-02-29"));
-#if defined(_AIX)
- TEST_EQUAL(stream_fr_FR_locale<CharT>(
- std::chrono::year_month_day{std::chrono::year{32'767}, std::chrono::month{12}, std::chrono::day{31}}),
- SV("+32767-12-31"));
-#elif defined(_WIN32) // defined(_AIX)
- TEST_EQUAL(stream_fr_FR_locale<CharT>(
- std::chrono::year_month_day{std::chrono::year{32'767}, std::chrono::month{12}, std::chrono::day{31}}),
- SV(""));
-#else // defined(_AIX)
TEST_EQUAL(stream_fr_FR_locale<CharT>(
std::chrono::year_month_day{std::chrono::year{32'767}, std::chrono::month{12}, std::chrono::day{31}}),
SV("32767-12-31"));
-#endif // defined(_AIX)
TEST_EQUAL(stream_ja_JP_locale<CharT>(
std::chrono::year_month_day{std::chrono::year{-32'768}, std::chrono::month{1}, std::chrono::day{1}}),
@@ -154,19 +130,9 @@ static void test() {
TEST_EQUAL(stream_ja_JP_locale<CharT>(
std::chrono::year_month_day{std::chrono::year{2000}, std::chrono::month{2}, std::chrono::day{29}}),
SV("2000-02-29"));
-#if defined(_AIX)
- TEST_EQUAL(stream_ja_JP_locale<CharT>(
- std::chrono::year_month_day{std::chrono::year{32'767}, std::chrono::month{12}, std::chrono::day{31}}),
- SV("+32767-12-31"));
-#elif defined(_WIN32) // defined(_AIX)
- TEST_EQUAL(stream_ja_JP_locale<CharT>(
- std::chrono::year_month_day{std::chrono::year{32'767}, std::chrono::month{12}, std::chrono::day{31}}),
- SV(""));
-#else // defined(_AIX)
TEST_EQUAL(stream_ja_JP_locale<CharT>(
std::chrono::year_month_day{std::chrono::year{32'767}, std::chrono::month{12}, std::chrono::day{31}}),
SV("32767-12-31"));
-#endif // defined(_AIX)
}
int main(int, char**) {
diff --git a/libcxx/test/std/time/time.clock/time.clock.system/sys_date.ostream.pass.cpp b/libcxx/test/std/time/time.clock/time.clock.system/sys_date.ostream.pass.cpp
index 7af3ebf7768072..c5645884cfed01 100644
--- a/libcxx/test/std/time/time.clock/time.clock.system/sys_date.ostream.pass.cpp
+++ b/libcxx/test/std/time/time.clock/time.clock.system/sys_date.ostream.pass.cpp
@@ -13,9 +13,6 @@
// TODO FMT This test should not require std::to_chars(floating-point)
// XFAIL: availability-fp_to_chars-missing
-// TODO FMT Investigate Windows issues.
-// XFAIL: msvc
-
// REQUIRES: locale.fr_FR.UTF-8
// REQUIRES: locale.ja_JP.UTF-8
@@ -81,20 +78,9 @@ static void test() {
TEST_EQUAL(stream_c_locale<CharT>(std::chrono::sys_days{
std::chrono::year_month_day{std::chrono::year{2000}, std::chrono::month{2}, std::chrono::day{29}}}),
SV("2000-02-29"));
-
-#if defined(_AIX)
- TEST_EQUAL(stream_c_locale<CharT>(std::chrono::sys_days{
- std::chrono::year_month_day{std::chrono::year{32'767}, std::chrono::month{12}, std::chrono::day{31}}}),
- SV("+32767-12-31"));
-#elif defined(_WIN32) // defined(_AIX)
- TEST_EQUAL(stream_c_locale<CharT>(std::chrono::sys_days{
- std::chrono::year_month_day{std::chrono::year{32'767}, std::chrono::month{12}, std::chrono::day{31}}}),
- SV(""));
-#else // defined(_AIX)
TEST_EQUAL(stream_c_locale<CharT>(std::chrono::sys_days{
std::chrono::year_month_day{std::chrono::year{32'767}, std::chrono::month{12}, std::chrono::day{31}}}),
SV("32767-12-31"));
-#endif // defined(_AIX)
// multiples of days are considered days.
TEST_EQUAL(stream_c_locale<CharT>(std::chrono::sys_time<std::chrono::weeks>{std::chrono::weeks{3}}),
@@ -112,19 +98,9 @@ static void test() {
TEST_EQUAL(stream_fr_FR_locale<CharT>(std::chrono::sys_days{
std::chrono::year_month_day{std::chrono::year{2000}, std::chrono::month{2}, std::chrono::day{29}}}),
SV("2000-02-29"));
-#if defined(_AIX)
- TEST_EQUAL(stream_fr_FR_locale<CharT>(std::chrono::sys_days{
- std::chrono::year_month_day{std::chrono::year{32'767}, std::chrono::month{12}, std::chrono::day{31}}}),
- SV("+32767-12-31"));
-#elif defined(_WIN32) // defined(_AIX)
- TEST_EQUAL(stream_fr_FR_locale<CharT>(std::chrono::sys_days{
- std::chrono::year_month_day{std::chrono::year{32'767}, std::chrono::month{12}, std::chrono::day{31}}}),
- SV(""));
-#else // defined(_AIX)
TEST_EQUAL(stream_fr_FR_locale<CharT>(std::chrono::sys_days{
std::chrono::year_month_day{std::chrono::year{32'767}, std::chrono::month{12}, std::chrono::day{31}}}),
SV("32767-12-31"));
-#endif // defined(_AIX)
// multiples of days are considered days.
TEST_EQUAL(stream_fr_FR_locale<CharT>(std::chrono::sys_time<std::chrono::weeks>{std::chrono::weeks{3}}),
@@ -142,19 +118,9 @@ static void test() {
TEST_EQUAL(stream_ja_JP_locale<CharT>(std::chrono::sys_days{
std::chrono::year_month_day{std::chrono::year{2000}, std::chrono::month{2}, std::chrono::day{29}}}),
SV("2000-02-29"));
-#if defined(_AIX)
- TEST_EQUAL(stream_ja_JP_locale<CharT>(std::chrono::sys_days{
- std::chrono::year_month_day{std::chrono::year{32'767}, std::chrono::month{12}, std::chrono::day{31}}}),
- SV("+32767-12-31"));
-#elif defined(_WIN32) // defined(_AIX)
- TEST_EQUAL(stream_ja_JP_locale<CharT>(std::chrono::sys_days{
- std::chrono::year_month_day{std::chrono::year{32'767}, std::chrono::month{12}, std::chrono::day{31}}}),
- SV(""));
-#else // defined(_AIX)
TEST_EQUAL(stream_ja_JP_locale<CharT>(std::chrono::sys_days{
std::chrono::year_month_day{std::chrono::year{32'767}, std::chrono::month{12}, std::chrono::day{31}}}),
SV("32767-12-31"));
-#endif // defined(_AIX)
// multiples of days are considered days.
TEST_EQUAL(stream_ja_JP_locale<CharT>(std::chrono::sys_time<std::chrono::weeks>{std::chrono::weeks{3}}),
diff --git a/libcxx/test/std/time/time.syn/formatter.year_month_day.pass.cpp b/libcxx/test/std/time/time.syn/formatter.year_month_day.pass.cpp
index 5a2b7afa37a865..1f2af1cb0530de 100644
--- a/libcxx/test/std/time/time.syn/formatter.year_month_day.pass.cpp
+++ b/libcxx/test/std/time/time.syn/formatter.year_month_day.pass.cpp
@@ -62,17 +62,6 @@ static void test_no_chrono_specs() {
std::chrono::year_month_day{std::chrono::year{1970}, std::chrono::month{2}, std::chrono::day{31}});
// Valid year, invalid month, valid day
-#ifdef _WIN32
- check(SV(" is not a valid date"),
- SV("{}"),
- std::chrono::year_month_day{std::chrono::year{1970}, std::chrono::month{0}, std::chrono::day{31}});
- check(SV("****** is not a valid date******"),
- SV("{:*^32}"),
- std::chrono::year_month_day{std::chrono::year{1970}, std::chrono::month{0}, std::chrono::day{31}});
- check(SV("*********** is not a valid date"),
- SV("{:*>31}"),
- std::chrono::year_month_day{std::chrono::year{1970}, std::chrono::month{0}, std::chrono::day{31}});
-#else // _WIN32
check(SV("1970-00-31 is not a valid date"),
SV("{}"),
std::chrono::year_month_day{std::chrono::year{1970}, std::chrono::month{0}, std::chrono::day{31}});
@@ -82,20 +71,8 @@ static void test_no_chrono_specs() {
check(SV("*1970-00-31 is not a valid date"),
SV("{:*>31}"),
std::chrono::year_month_day{std::chrono::year{1970}, std::chrono::month{0}, std::chrono::day{31}});
-#endif // _WIN32
// Valid year, invalid month, invalid day
-#ifdef _WIN32
- check(SV(" is not a valid date"),
- SV("{}"),
- std::chrono::year_month_day{std::chrono::year{1970}, std::chrono::month{0}, std::chrono::day{32}});
- check(SV("****** is not a valid date******"),
- SV("{:*^32}"),
- std::chrono::year_month_day{std::chrono::year{1970}, std::chrono::month{0}, std::chrono::day{32}});
- check(SV("*********** is not a valid date"),
- SV("{:*>31}"),
- std::chrono::year_month_day{std::chrono::year{1970}, std::chrono::month{0}, std::chrono::day{32}});
-#else // _WIN32
check(SV("1970-00-32 is not a valid date"),
SV("{}"),
std::chrono::year_month_day{std::chrono::year{1970}, std::chrono::month{0}, std::chrono::day{32}});
@@ -105,7 +82,6 @@ static void test_no_chrono_specs() {
check(SV("*1970-00-32 is not a valid date"),
SV("{:*>31}"),
std::chrono::year_month_day{std::chrono::year{1970}, std::chrono::month{0}, std::chrono::day{32}});
-#endif // _WIN32
// Invalid year, valid month, valid day
check(SV("-32768-01-31 is not a valid date"),
More information about the libcxx-commits
mailing list