summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark de Wever <koraq@xs4all.nl>2024-04-23 19:42:00 +0200
committerGitHub <noreply@github.com>2024-04-23 19:42:00 +0200
commit579d30109ae9526ea3ec89d2cadc846bd8cffae5 (patch)
treea1b676621e545f91c035ed1ab0dd21894ab4d1d2
parent3a9d8cd5fc5e07629b46901accb1884eae1af694 (diff)
[libc++][chrono] Fixes format output of negative values. (#89408)
When trying to express a time before the epoch (e.g. "one nanosecond before 00:01:40 on 1900-01-01") the date would be shown as: 1900-01-01 00:01:39.-00000001 After this patch, that time would be correctly shown as: 1900-01-01 00:01:39.999999999
-rw-r--r--libcxx/include/__chrono/formatter.h3
-rw-r--r--libcxx/test/std/time/time.clock/time.clock.file/ostream.pass.cpp109
-rw-r--r--libcxx/test/std/time/time.clock/time.clock.local/ostream.pass.cpp54
-rw-r--r--libcxx/test/std/time/time.clock/time.clock.system/sys_time.ostream.pass.cpp54
4 files changed, 220 insertions, 0 deletions
diff --git a/libcxx/include/__chrono/formatter.h b/libcxx/include/__chrono/formatter.h
index 226fccbee6d1..e9b81c3de8a7 100644
--- a/libcxx/include/__chrono/formatter.h
+++ b/libcxx/include/__chrono/formatter.h
@@ -88,6 +88,9 @@ __format_sub_seconds(basic_stringstream<_CharT>& __sstr, const chrono::duration<
using __duration = chrono::duration<_Rep, _Period>;
auto __fraction = __value - chrono::duration_cast<chrono::seconds>(__value);
+ // Converts a negative fraction to its positive value.
+ if (__value < chrono::seconds{0} && __fraction != __duration{0})
+ __fraction += chrono::seconds{1};
if constexpr (chrono::treat_as_floating_point_v<_Rep>)
// When the floating-point value has digits itself they are ignored based
// on the wording in [tab:time.format.spec]
diff --git a/libcxx/test/std/time/time.clock/time.clock.file/ostream.pass.cpp b/libcxx/test/std/time/time.clock/time.clock.file/ostream.pass.cpp
index 18a4506b9156..11eab1dddfe3 100644
--- a/libcxx/test/std/time/time.clock/time.clock.file/ostream.pass.cpp
+++ b/libcxx/test/std/time/time.clock/time.clock.file/ostream.pass.cpp
@@ -71,8 +71,45 @@ template <class CharT>
static void test_c() {
using namespace std::literals::chrono_literals;
+ assert(stream_c_locale<CharT>(std::chrono::file_time<std::chrono::nanoseconds>{-946'688'523'123'456'789ns}) ==
+ SV("1940-01-01 22:57:56.876543211"));
+
+ assert(stream_c_locale<CharT>(std::chrono::file_time<std::chrono::microseconds>{-946'688'523'123'456us}) ==
+ SV("1940-01-01 22:57:56.876544"));
+
+ assert(stream_c_locale<CharT>(std::chrono::file_time<std::chrono::milliseconds>{-946'688'523'123ms}) ==
+ SV("1940-01-01 22:57:56.877"));
+
+ assert(stream_c_locale<CharT>(std::chrono::file_time<std::chrono::nanoseconds>{-1000000000ns}) ==
+ SV("1969-12-31 23:59:59.000000000"));
+
+ assert(stream_c_locale<CharT>(std::chrono::file_time<std::chrono::microseconds>{-1000000us}) ==
+ SV("1969-12-31 23:59:59.000000"));
+
+ assert(stream_c_locale<CharT>(std::chrono::file_time<std::chrono::milliseconds>{-1000ms}) ==
+ SV("1969-12-31 23:59:59.000"));
+
+ assert(stream_c_locale<CharT>(std::chrono::file_time<std::chrono::nanoseconds>{-1ns}) ==
+ SV("1969-12-31 23:59:59.999999999"));
+
+ assert(stream_c_locale<CharT>(std::chrono::file_time<std::chrono::nanoseconds>{0ns}) ==
+ SV("1970-01-01 00:00:00.000000000"));
+
+ assert(stream_c_locale<CharT>(std::chrono::file_time<std::chrono::nanoseconds>{1ns}) ==
+ SV("1970-01-01 00:00:00.000000001"));
+
+ assert(stream_c_locale<CharT>(std::chrono::file_time<std::chrono::nanoseconds>{1000000000ns}) ==
+ SV("1970-01-01 00:00:01.000000000"));
+
+ assert(stream_c_locale<CharT>(std::chrono::file_time<std::chrono::microseconds>{1000000us}) ==
+ SV("1970-01-01 00:00:01.000000"));
+
+ assert(stream_c_locale<CharT>(std::chrono::file_time<std::chrono::milliseconds>{1000ms}) ==
+ SV("1970-01-01 00:00:01.000"));
+
assert(stream_c_locale<CharT>(file_time<std::chrono::nanoseconds>{946'688'523'123'456'789ns}) ==
SV("2000-01-01 01:02:03.123456789"));
+
assert(stream_c_locale<CharT>(file_time<std::chrono::microseconds>{946'688'523'123'456us}) ==
SV("2000-01-01 01:02:03.123456"));
@@ -107,6 +144,42 @@ template <class CharT>
static void test_fr_FR() {
using namespace std::literals::chrono_literals;
+ assert(stream_fr_FR_locale<CharT>(std::chrono::file_time<std::chrono::nanoseconds>{-946'688'523'123'456'789ns}) ==
+ SV("1940-01-01 22:57:56,876543211"));
+
+ assert(stream_fr_FR_locale<CharT>(std::chrono::file_time<std::chrono::microseconds>{-946'688'523'123'456us}) ==
+ SV("1940-01-01 22:57:56,876544"));
+
+ assert(stream_fr_FR_locale<CharT>(std::chrono::file_time<std::chrono::milliseconds>{-946'688'523'123ms}) ==
+ SV("1940-01-01 22:57:56,877"));
+
+ assert(stream_fr_FR_locale<CharT>(std::chrono::file_time<std::chrono::nanoseconds>{-1000000000ns}) ==
+ SV("1969-12-31 23:59:59,000000000"));
+
+ assert(stream_fr_FR_locale<CharT>(std::chrono::file_time<std::chrono::microseconds>{-1000000us}) ==
+ SV("1969-12-31 23:59:59,000000"));
+
+ assert(stream_fr_FR_locale<CharT>(std::chrono::file_time<std::chrono::milliseconds>{-1000ms}) ==
+ SV("1969-12-31 23:59:59,000"));
+
+ assert(stream_fr_FR_locale<CharT>(std::chrono::file_time<std::chrono::nanoseconds>{-1ns}) ==
+ SV("1969-12-31 23:59:59,999999999"));
+
+ assert(stream_fr_FR_locale<CharT>(std::chrono::file_time<std::chrono::nanoseconds>{0ns}) ==
+ SV("1970-01-01 00:00:00,000000000"));
+
+ assert(stream_fr_FR_locale<CharT>(std::chrono::file_time<std::chrono::nanoseconds>{1ns}) ==
+ SV("1970-01-01 00:00:00,000000001"));
+
+ assert(stream_fr_FR_locale<CharT>(std::chrono::file_time<std::chrono::nanoseconds>{1000000000ns}) ==
+ SV("1970-01-01 00:00:01,000000000"));
+
+ assert(stream_fr_FR_locale<CharT>(std::chrono::file_time<std::chrono::microseconds>{1000000us}) ==
+ SV("1970-01-01 00:00:01,000000"));
+
+ assert(stream_fr_FR_locale<CharT>(std::chrono::file_time<std::chrono::milliseconds>{1000ms}) ==
+ SV("1970-01-01 00:00:01,000"));
+
assert(stream_fr_FR_locale<CharT>(file_time<std::chrono::nanoseconds>{946'688'523'123'456'789ns}) ==
SV("2000-01-01 01:02:03,123456789"));
assert(stream_fr_FR_locale<CharT>(file_time<std::chrono::microseconds>{946'688'523'123'456us}) ==
@@ -144,6 +217,42 @@ template <class CharT>
static void test_ja_JP() {
using namespace std::literals::chrono_literals;
+ assert(stream_ja_JP_locale<CharT>(std::chrono::file_time<std::chrono::nanoseconds>{-946'688'523'123'456'789ns}) ==
+ SV("1940-01-01 22:57:56.876543211"));
+
+ assert(stream_ja_JP_locale<CharT>(std::chrono::file_time<std::chrono::microseconds>{-946'688'523'123'456us}) ==
+ SV("1940-01-01 22:57:56.876544"));
+
+ assert(stream_ja_JP_locale<CharT>(std::chrono::file_time<std::chrono::milliseconds>{-946'688'523'123ms}) ==
+ SV("1940-01-01 22:57:56.877"));
+
+ assert(stream_ja_JP_locale<CharT>(std::chrono::file_time<std::chrono::nanoseconds>{-1000000000ns}) ==
+ SV("1969-12-31 23:59:59.000000000"));
+
+ assert(stream_ja_JP_locale<CharT>(std::chrono::file_time<std::chrono::microseconds>{-1000000us}) ==
+ SV("1969-12-31 23:59:59.000000"));
+
+ assert(stream_ja_JP_locale<CharT>(std::chrono::file_time<std::chrono::milliseconds>{-1000ms}) ==
+ SV("1969-12-31 23:59:59.000"));
+
+ assert(stream_ja_JP_locale<CharT>(std::chrono::file_time<std::chrono::nanoseconds>{-1ns}) ==
+ SV("1969-12-31 23:59:59.999999999"));
+
+ assert(stream_ja_JP_locale<CharT>(std::chrono::file_time<std::chrono::nanoseconds>{0ns}) ==
+ SV("1970-01-01 00:00:00.000000000"));
+
+ assert(stream_ja_JP_locale<CharT>(std::chrono::file_time<std::chrono::nanoseconds>{1ns}) ==
+ SV("1970-01-01 00:00:00.000000001"));
+
+ assert(stream_ja_JP_locale<CharT>(std::chrono::file_time<std::chrono::nanoseconds>{1000000000ns}) ==
+ SV("1970-01-01 00:00:01.000000000"));
+
+ assert(stream_ja_JP_locale<CharT>(std::chrono::file_time<std::chrono::microseconds>{1000000us}) ==
+ SV("1970-01-01 00:00:01.000000"));
+
+ assert(stream_ja_JP_locale<CharT>(std::chrono::file_time<std::chrono::milliseconds>{1000ms}) ==
+ SV("1970-01-01 00:00:01.000"));
+
assert(stream_ja_JP_locale<CharT>(file_time<std::chrono::nanoseconds>{946'688'523'123'456'789ns}) ==
SV("2000-01-01 01:02:03.123456789"));
assert(stream_ja_JP_locale<CharT>(file_time<std::chrono::microseconds>{946'688'523'123'456us}) ==
diff --git a/libcxx/test/std/time/time.clock/time.clock.local/ostream.pass.cpp b/libcxx/test/std/time/time.clock/time.clock.local/ostream.pass.cpp
index 9fdef8d5adc7..6ec63a14fbbd 100644
--- a/libcxx/test/std/time/time.clock/time.clock.local/ostream.pass.cpp
+++ b/libcxx/test/std/time/time.clock/time.clock.local/ostream.pass.cpp
@@ -64,6 +64,24 @@ template <class CharT>
static void test_c() {
using namespace std::literals::chrono_literals;
+ assert(stream_c_locale<CharT>(std::chrono::local_time<std::chrono::nanoseconds>{-946'688'523'123'456'789ns}) ==
+ SV("1940-01-01 22:57:56.876543211"));
+
+ assert(stream_c_locale<CharT>(std::chrono::local_time<std::chrono::microseconds>{-946'688'523'123'456us}) ==
+ SV("1940-01-01 22:57:56.876544"));
+
+ assert(stream_c_locale<CharT>(std::chrono::local_time<std::chrono::milliseconds>{-946'688'523'123ms}) ==
+ SV("1940-01-01 22:57:56.877"));
+
+ assert(stream_c_locale<CharT>(std::chrono::local_time<std::chrono::nanoseconds>{-1ns}) ==
+ SV("1969-12-31 23:59:59.999999999"));
+
+ assert(stream_c_locale<CharT>(std::chrono::local_time<std::chrono::nanoseconds>{0ns}) ==
+ SV("1970-01-01 00:00:00.000000000"));
+
+ assert(stream_c_locale<CharT>(std::chrono::local_time<std::chrono::nanoseconds>{1ns}) ==
+ SV("1970-01-01 00:00:00.000000001"));
+
assert(stream_c_locale<CharT>(std::chrono::local_time<std::chrono::nanoseconds>{946'688'523'123'456'789ns}) ==
SV("2000-01-01 01:02:03.123456789"));
assert(stream_c_locale<CharT>(std::chrono::local_time<std::chrono::microseconds>{946'688'523'123'456us}) ==
@@ -97,6 +115,24 @@ template <class CharT>
static void test_fr_FR() {
using namespace std::literals::chrono_literals;
+ assert(stream_fr_FR_locale<CharT>(std::chrono::local_time<std::chrono::nanoseconds>{-946'688'523'123'456'789ns}) ==
+ SV("1940-01-01 22:57:56,876543211"));
+
+ assert(stream_fr_FR_locale<CharT>(std::chrono::local_time<std::chrono::microseconds>{-946'688'523'123'456us}) ==
+ SV("1940-01-01 22:57:56,876544"));
+
+ assert(stream_fr_FR_locale<CharT>(std::chrono::local_time<std::chrono::milliseconds>{-946'688'523'123ms}) ==
+ SV("1940-01-01 22:57:56,877"));
+
+ assert(stream_fr_FR_locale<CharT>(std::chrono::local_time<std::chrono::nanoseconds>{-1ns}) ==
+ SV("1969-12-31 23:59:59,999999999"));
+
+ assert(stream_fr_FR_locale<CharT>(std::chrono::local_time<std::chrono::nanoseconds>{0ns}) ==
+ SV("1970-01-01 00:00:00,000000000"));
+
+ assert(stream_fr_FR_locale<CharT>(std::chrono::local_time<std::chrono::nanoseconds>{1ns}) ==
+ SV("1970-01-01 00:00:00,000000001"));
+
assert(stream_fr_FR_locale<CharT>(std::chrono::local_time<std::chrono::nanoseconds>{946'688'523'123'456'789ns}) ==
SV("2000-01-01 01:02:03,123456789"));
assert(stream_fr_FR_locale<CharT>(std::chrono::local_time<std::chrono::microseconds>{946'688'523'123'456us}) ==
@@ -131,6 +167,24 @@ template <class CharT>
static void test_ja_JP() {
using namespace std::literals::chrono_literals;
+ assert(stream_ja_JP_locale<CharT>(std::chrono::local_time<std::chrono::nanoseconds>{-946'688'523'123'456'789ns}) ==
+ SV("1940-01-01 22:57:56.876543211"));
+
+ assert(stream_ja_JP_locale<CharT>(std::chrono::local_time<std::chrono::microseconds>{-946'688'523'123'456us}) ==
+ SV("1940-01-01 22:57:56.876544"));
+
+ assert(stream_ja_JP_locale<CharT>(std::chrono::local_time<std::chrono::milliseconds>{-946'688'523'123ms}) ==
+ SV("1940-01-01 22:57:56.877"));
+
+ assert(stream_ja_JP_locale<CharT>(std::chrono::local_time<std::chrono::nanoseconds>{-1ns}) ==
+ SV("1969-12-31 23:59:59.999999999"));
+
+ assert(stream_ja_JP_locale<CharT>(std::chrono::local_time<std::chrono::nanoseconds>{0ns}) ==
+ SV("1970-01-01 00:00:00.000000000"));
+
+ assert(stream_ja_JP_locale<CharT>(std::chrono::local_time<std::chrono::nanoseconds>{1ns}) ==
+ SV("1970-01-01 00:00:00.000000001"));
+
assert(stream_ja_JP_locale<CharT>(std::chrono::local_time<std::chrono::nanoseconds>{946'688'523'123'456'789ns}) ==
SV("2000-01-01 01:02:03.123456789"));
assert(stream_ja_JP_locale<CharT>(std::chrono::local_time<std::chrono::microseconds>{946'688'523'123'456us}) ==
diff --git a/libcxx/test/std/time/time.clock/time.clock.system/sys_time.ostream.pass.cpp b/libcxx/test/std/time/time.clock/time.clock.system/sys_time.ostream.pass.cpp
index 78d8da57c150..e596ddefde51 100644
--- a/libcxx/test/std/time/time.clock/time.clock.system/sys_time.ostream.pass.cpp
+++ b/libcxx/test/std/time/time.clock/time.clock.system/sys_time.ostream.pass.cpp
@@ -64,6 +64,24 @@ template <class CharT>
static void test_c() {
using namespace std::literals::chrono_literals;
+ assert(stream_c_locale<CharT>(std::chrono::sys_time<std::chrono::nanoseconds>{-946'688'523'123'456'789ns}) ==
+ SV("1940-01-01 22:57:56.876543211"));
+
+ assert(stream_c_locale<CharT>(std::chrono::sys_time<std::chrono::microseconds>{-946'688'523'123'456us}) ==
+ SV("1940-01-01 22:57:56.876544"));
+
+ assert(stream_c_locale<CharT>(std::chrono::sys_time<std::chrono::milliseconds>{-946'688'523'123ms}) ==
+ SV("1940-01-01 22:57:56.877"));
+
+ assert(stream_c_locale<CharT>(std::chrono::sys_time<std::chrono::nanoseconds>{-1ns}) ==
+ SV("1969-12-31 23:59:59.999999999"));
+
+ assert(stream_c_locale<CharT>(std::chrono::sys_time<std::chrono::nanoseconds>{0ns}) ==
+ SV("1970-01-01 00:00:00.000000000"));
+
+ assert(stream_c_locale<CharT>(std::chrono::sys_time<std::chrono::nanoseconds>{1ns}) ==
+ SV("1970-01-01 00:00:00.000000001"));
+
assert(stream_c_locale<CharT>(std::chrono::sys_time<std::chrono::nanoseconds>{946'688'523'123'456'789ns}) ==
SV("2000-01-01 01:02:03.123456789"));
assert(stream_c_locale<CharT>(std::chrono::sys_time<std::chrono::microseconds>{946'688'523'123'456us}) ==
@@ -92,6 +110,24 @@ template <class CharT>
static void test_fr_FR() {
using namespace std::literals::chrono_literals;
+ assert(stream_fr_FR_locale<CharT>(std::chrono::sys_time<std::chrono::nanoseconds>{-946'688'523'123'456'789ns}) ==
+ SV("1940-01-01 22:57:56,876543211"));
+
+ assert(stream_fr_FR_locale<CharT>(std::chrono::sys_time<std::chrono::microseconds>{-946'688'523'123'456us}) ==
+ SV("1940-01-01 22:57:56,876544"));
+
+ assert(stream_fr_FR_locale<CharT>(std::chrono::sys_time<std::chrono::milliseconds>{-946'688'523'123ms}) ==
+ SV("1940-01-01 22:57:56,877"));
+
+ assert(stream_fr_FR_locale<CharT>(std::chrono::sys_time<std::chrono::nanoseconds>{-1ns}) ==
+ SV("1969-12-31 23:59:59,999999999"));
+
+ assert(stream_fr_FR_locale<CharT>(std::chrono::sys_time<std::chrono::nanoseconds>{0ns}) ==
+ SV("1970-01-01 00:00:00,000000000"));
+
+ assert(stream_fr_FR_locale<CharT>(std::chrono::sys_time<std::chrono::nanoseconds>{1ns}) ==
+ SV("1970-01-01 00:00:00,000000001"));
+
assert(stream_fr_FR_locale<CharT>(std::chrono::sys_time<std::chrono::nanoseconds>{946'688'523'123'456'789ns}) ==
SV("2000-01-01 01:02:03,123456789"));
assert(stream_fr_FR_locale<CharT>(std::chrono::sys_time<std::chrono::microseconds>{946'688'523'123'456us}) ==
@@ -120,6 +156,24 @@ template <class CharT>
static void test_ja_JP() {
using namespace std::literals::chrono_literals;
+ assert(stream_ja_JP_locale<CharT>(std::chrono::sys_time<std::chrono::nanoseconds>{-946'688'523'123'456'789ns}) ==
+ SV("1940-01-01 22:57:56.876543211"));
+
+ assert(stream_ja_JP_locale<CharT>(std::chrono::sys_time<std::chrono::microseconds>{-946'688'523'123'456us}) ==
+ SV("1940-01-01 22:57:56.876544"));
+
+ assert(stream_ja_JP_locale<CharT>(std::chrono::sys_time<std::chrono::milliseconds>{-946'688'523'123ms}) ==
+ SV("1940-01-01 22:57:56.877"));
+
+ assert(stream_ja_JP_locale<CharT>(std::chrono::sys_time<std::chrono::nanoseconds>{-1ns}) ==
+ SV("1969-12-31 23:59:59.999999999"));
+
+ assert(stream_ja_JP_locale<CharT>(std::chrono::sys_time<std::chrono::nanoseconds>{0ns}) ==
+ SV("1970-01-01 00:00:00.000000000"));
+
+ assert(stream_ja_JP_locale<CharT>(std::chrono::sys_time<std::chrono::nanoseconds>{1ns}) ==
+ SV("1970-01-01 00:00:00.000000001"));
+
assert(stream_ja_JP_locale<CharT>(std::chrono::sys_time<std::chrono::nanoseconds>{946'688'523'123'456'789ns}) ==
SV("2000-01-01 01:02:03.123456789"));
assert(stream_ja_JP_locale<CharT>(std::chrono::sys_time<std::chrono::microseconds>{946'688'523'123'456us}) ==