-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[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
Conversation
@llvm/pr-subscribers-libcxx Author: Mark de Wever (mordante) ChangesThe 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:
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"),
|
0aeab5a
to
f3e7b58
Compare
6327aee
to
cb87ecc
Compare
f3e7b58
to
677956d
Compare
cb87ecc
to
d39b5b5
Compare
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.
677956d
to
96fbdc0
Compare
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.