Skip to content

[libc++][chrono] Improves date formatting. #86127

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 17, 2024

Conversation

mordante
Copy link
Member

@mordante mordante commented Mar 21, 2024

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. None 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.

@mordante mordante requested a review from a team as a code owner March 21, 2024 14:35
@llvmbot llvmbot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Mar 21, 2024
@llvmbot
Copy link
Member

llvmbot commented Mar 21, 2024

@llvm/pr-subscribers-libcxx

Author: Mark de Wever (mordante)

Changes

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.


Full diff: https://github.com/llvm/llvm-project/pull/86127.diff

4 Files Affected:

  • (modified) libcxx/include/__chrono/formatter.h (+7-9)
  • (modified) libcxx/test/std/time/time.cal/time.cal.ymd/time.cal.ymd.nonmembers/ostream.pass.cpp (-31)
  • (modified) libcxx/test/std/time/time.clock/time.clock.system/sys_date.ostream.pass.cpp (-31)
  • (modified) libcxx/test/std/time/time.syn/formatter.year_month_day.pass.cpp (-24)
diff --git a/libcxx/include/__chrono/formatter.h b/libcxx/include/__chrono/formatter.h
index 8b8592041a1fb9..217979e88c93db 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. Intead of 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..3a37e75bbcd2e4 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
@@ -89,20 +89,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 +111,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 +133,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..1523b993555478 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
@@ -81,20 +81,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 +101,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 +121,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"),

@mordante mordante force-pushed the users/mordante/improves_chrono_year_formatting branch from 0aeab5a to f3e7b58 Compare March 21, 2024 17:00
@mordante mordante force-pushed the users/mordante/fixes_chrono_formatter_time_zone_information branch from 6327aee to cb87ecc Compare April 10, 2024 15:58
@mordante mordante force-pushed the users/mordante/improves_chrono_year_formatting branch from f3e7b58 to 677956d Compare April 10, 2024 18:45
@ldionne ldionne self-assigned this Apr 16, 2024
@mordante mordante force-pushed the users/mordante/fixes_chrono_formatter_time_zone_information branch from cb87ecc to d39b5b5 Compare April 16, 2024 18:16
Base automatically changed from users/mordante/fixes_chrono_formatter_time_zone_information to main April 17, 2024 05:59
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.
@mordante mordante force-pushed the users/mordante/improves_chrono_year_formatting branch from 677956d to 96fbdc0 Compare April 17, 2024 06:09
@mordante mordante merged commit 812963f into main Apr 17, 2024
@mordante mordante deleted the users/mordante/improves_chrono_year_formatting branch April 17, 2024 15:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants