[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