-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[libc++][chrono] Fixes format output of negative values. #89408
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
mordante
merged 2 commits into
main
from
users/mordante/fixes_formatting_timepoints_before_epoch
Apr 23, 2024
Merged
[libc++][chrono] Fixes format output of negative values. #89408
mordante
merged 2 commits into
main
from
users/mordante/fixes_formatting_timepoints_before_epoch
Apr 23, 2024
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@llvm/pr-subscribers-libcxx Author: Mark de Wever (mordante) ChangesThe negative values were shown as 1900-01-01 00:01:39.-00000001 after the changes they are shown as 1900-01-01 00:01:39.999999999 Full diff: https://github.com/llvm/llvm-project/pull/89408.diff 4 Files Affected:
diff --git a/libcxx/include/__chrono/formatter.h b/libcxx/include/__chrono/formatter.h
index 226fccbee6d133..058e9ac97bc941 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 += 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 18a4506b91566b..99d56002e9c391 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,6 +71,24 @@ 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>{-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>(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}) ==
@@ -107,6 +125,24 @@ 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>{-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>(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 +180,24 @@ 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>{-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>(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 9fdef8d5adc782..6ec63a14fbbd33 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 78d8da57c150a6..e596ddefde51d9 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}) ==
|
The negative values were shown as 1900-01-01 00:01:39.-00000001 after the changes they are shown as 1900-01-01 00:01:39.999999999
11fa6e8
to
d37de3b
Compare
ldionne
approved these changes
Apr 23, 2024
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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