Skip to content

Commit 579d301

Browse files
authored
[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
1 parent 3a9d8cd commit 579d301

File tree

4 files changed

+220
-0
lines changed

4 files changed

+220
-0
lines changed

libcxx/include/__chrono/formatter.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@ __format_sub_seconds(basic_stringstream<_CharT>& __sstr, const chrono::duration<
8888
using __duration = chrono::duration<_Rep, _Period>;
8989

9090
auto __fraction = __value - chrono::duration_cast<chrono::seconds>(__value);
91+
// Converts a negative fraction to its positive value.
92+
if (__value < chrono::seconds{0} && __fraction != __duration{0})
93+
__fraction += chrono::seconds{1};
9194
if constexpr (chrono::treat_as_floating_point_v<_Rep>)
9295
// When the floating-point value has digits itself they are ignored based
9396
// on the wording in [tab:time.format.spec]

libcxx/test/std/time/time.clock/time.clock.file/ostream.pass.cpp

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,45 @@ template <class CharT>
7171
static void test_c() {
7272
using namespace std::literals::chrono_literals;
7373

74+
assert(stream_c_locale<CharT>(std::chrono::file_time<std::chrono::nanoseconds>{-946'688'523'123'456'789ns}) ==
75+
SV("1940-01-01 22:57:56.876543211"));
76+
77+
assert(stream_c_locale<CharT>(std::chrono::file_time<std::chrono::microseconds>{-946'688'523'123'456us}) ==
78+
SV("1940-01-01 22:57:56.876544"));
79+
80+
assert(stream_c_locale<CharT>(std::chrono::file_time<std::chrono::milliseconds>{-946'688'523'123ms}) ==
81+
SV("1940-01-01 22:57:56.877"));
82+
83+
assert(stream_c_locale<CharT>(std::chrono::file_time<std::chrono::nanoseconds>{-1000000000ns}) ==
84+
SV("1969-12-31 23:59:59.000000000"));
85+
86+
assert(stream_c_locale<CharT>(std::chrono::file_time<std::chrono::microseconds>{-1000000us}) ==
87+
SV("1969-12-31 23:59:59.000000"));
88+
89+
assert(stream_c_locale<CharT>(std::chrono::file_time<std::chrono::milliseconds>{-1000ms}) ==
90+
SV("1969-12-31 23:59:59.000"));
91+
92+
assert(stream_c_locale<CharT>(std::chrono::file_time<std::chrono::nanoseconds>{-1ns}) ==
93+
SV("1969-12-31 23:59:59.999999999"));
94+
95+
assert(stream_c_locale<CharT>(std::chrono::file_time<std::chrono::nanoseconds>{0ns}) ==
96+
SV("1970-01-01 00:00:00.000000000"));
97+
98+
assert(stream_c_locale<CharT>(std::chrono::file_time<std::chrono::nanoseconds>{1ns}) ==
99+
SV("1970-01-01 00:00:00.000000001"));
100+
101+
assert(stream_c_locale<CharT>(std::chrono::file_time<std::chrono::nanoseconds>{1000000000ns}) ==
102+
SV("1970-01-01 00:00:01.000000000"));
103+
104+
assert(stream_c_locale<CharT>(std::chrono::file_time<std::chrono::microseconds>{1000000us}) ==
105+
SV("1970-01-01 00:00:01.000000"));
106+
107+
assert(stream_c_locale<CharT>(std::chrono::file_time<std::chrono::milliseconds>{1000ms}) ==
108+
SV("1970-01-01 00:00:01.000"));
109+
74110
assert(stream_c_locale<CharT>(file_time<std::chrono::nanoseconds>{946'688'523'123'456'789ns}) ==
75111
SV("2000-01-01 01:02:03.123456789"));
112+
76113
assert(stream_c_locale<CharT>(file_time<std::chrono::microseconds>{946'688'523'123'456us}) ==
77114
SV("2000-01-01 01:02:03.123456"));
78115

@@ -107,6 +144,42 @@ template <class CharT>
107144
static void test_fr_FR() {
108145
using namespace std::literals::chrono_literals;
109146

147+
assert(stream_fr_FR_locale<CharT>(std::chrono::file_time<std::chrono::nanoseconds>{-946'688'523'123'456'789ns}) ==
148+
SV("1940-01-01 22:57:56,876543211"));
149+
150+
assert(stream_fr_FR_locale<CharT>(std::chrono::file_time<std::chrono::microseconds>{-946'688'523'123'456us}) ==
151+
SV("1940-01-01 22:57:56,876544"));
152+
153+
assert(stream_fr_FR_locale<CharT>(std::chrono::file_time<std::chrono::milliseconds>{-946'688'523'123ms}) ==
154+
SV("1940-01-01 22:57:56,877"));
155+
156+
assert(stream_fr_FR_locale<CharT>(std::chrono::file_time<std::chrono::nanoseconds>{-1000000000ns}) ==
157+
SV("1969-12-31 23:59:59,000000000"));
158+
159+
assert(stream_fr_FR_locale<CharT>(std::chrono::file_time<std::chrono::microseconds>{-1000000us}) ==
160+
SV("1969-12-31 23:59:59,000000"));
161+
162+
assert(stream_fr_FR_locale<CharT>(std::chrono::file_time<std::chrono::milliseconds>{-1000ms}) ==
163+
SV("1969-12-31 23:59:59,000"));
164+
165+
assert(stream_fr_FR_locale<CharT>(std::chrono::file_time<std::chrono::nanoseconds>{-1ns}) ==
166+
SV("1969-12-31 23:59:59,999999999"));
167+
168+
assert(stream_fr_FR_locale<CharT>(std::chrono::file_time<std::chrono::nanoseconds>{0ns}) ==
169+
SV("1970-01-01 00:00:00,000000000"));
170+
171+
assert(stream_fr_FR_locale<CharT>(std::chrono::file_time<std::chrono::nanoseconds>{1ns}) ==
172+
SV("1970-01-01 00:00:00,000000001"));
173+
174+
assert(stream_fr_FR_locale<CharT>(std::chrono::file_time<std::chrono::nanoseconds>{1000000000ns}) ==
175+
SV("1970-01-01 00:00:01,000000000"));
176+
177+
assert(stream_fr_FR_locale<CharT>(std::chrono::file_time<std::chrono::microseconds>{1000000us}) ==
178+
SV("1970-01-01 00:00:01,000000"));
179+
180+
assert(stream_fr_FR_locale<CharT>(std::chrono::file_time<std::chrono::milliseconds>{1000ms}) ==
181+
SV("1970-01-01 00:00:01,000"));
182+
110183
assert(stream_fr_FR_locale<CharT>(file_time<std::chrono::nanoseconds>{946'688'523'123'456'789ns}) ==
111184
SV("2000-01-01 01:02:03,123456789"));
112185
assert(stream_fr_FR_locale<CharT>(file_time<std::chrono::microseconds>{946'688'523'123'456us}) ==
@@ -144,6 +217,42 @@ template <class CharT>
144217
static void test_ja_JP() {
145218
using namespace std::literals::chrono_literals;
146219

220+
assert(stream_ja_JP_locale<CharT>(std::chrono::file_time<std::chrono::nanoseconds>{-946'688'523'123'456'789ns}) ==
221+
SV("1940-01-01 22:57:56.876543211"));
222+
223+
assert(stream_ja_JP_locale<CharT>(std::chrono::file_time<std::chrono::microseconds>{-946'688'523'123'456us}) ==
224+
SV("1940-01-01 22:57:56.876544"));
225+
226+
assert(stream_ja_JP_locale<CharT>(std::chrono::file_time<std::chrono::milliseconds>{-946'688'523'123ms}) ==
227+
SV("1940-01-01 22:57:56.877"));
228+
229+
assert(stream_ja_JP_locale<CharT>(std::chrono::file_time<std::chrono::nanoseconds>{-1000000000ns}) ==
230+
SV("1969-12-31 23:59:59.000000000"));
231+
232+
assert(stream_ja_JP_locale<CharT>(std::chrono::file_time<std::chrono::microseconds>{-1000000us}) ==
233+
SV("1969-12-31 23:59:59.000000"));
234+
235+
assert(stream_ja_JP_locale<CharT>(std::chrono::file_time<std::chrono::milliseconds>{-1000ms}) ==
236+
SV("1969-12-31 23:59:59.000"));
237+
238+
assert(stream_ja_JP_locale<CharT>(std::chrono::file_time<std::chrono::nanoseconds>{-1ns}) ==
239+
SV("1969-12-31 23:59:59.999999999"));
240+
241+
assert(stream_ja_JP_locale<CharT>(std::chrono::file_time<std::chrono::nanoseconds>{0ns}) ==
242+
SV("1970-01-01 00:00:00.000000000"));
243+
244+
assert(stream_ja_JP_locale<CharT>(std::chrono::file_time<std::chrono::nanoseconds>{1ns}) ==
245+
SV("1970-01-01 00:00:00.000000001"));
246+
247+
assert(stream_ja_JP_locale<CharT>(std::chrono::file_time<std::chrono::nanoseconds>{1000000000ns}) ==
248+
SV("1970-01-01 00:00:01.000000000"));
249+
250+
assert(stream_ja_JP_locale<CharT>(std::chrono::file_time<std::chrono::microseconds>{1000000us}) ==
251+
SV("1970-01-01 00:00:01.000000"));
252+
253+
assert(stream_ja_JP_locale<CharT>(std::chrono::file_time<std::chrono::milliseconds>{1000ms}) ==
254+
SV("1970-01-01 00:00:01.000"));
255+
147256
assert(stream_ja_JP_locale<CharT>(file_time<std::chrono::nanoseconds>{946'688'523'123'456'789ns}) ==
148257
SV("2000-01-01 01:02:03.123456789"));
149258
assert(stream_ja_JP_locale<CharT>(file_time<std::chrono::microseconds>{946'688'523'123'456us}) ==

libcxx/test/std/time/time.clock/time.clock.local/ostream.pass.cpp

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,24 @@ template <class CharT>
6464
static void test_c() {
6565
using namespace std::literals::chrono_literals;
6666

67+
assert(stream_c_locale<CharT>(std::chrono::local_time<std::chrono::nanoseconds>{-946'688'523'123'456'789ns}) ==
68+
SV("1940-01-01 22:57:56.876543211"));
69+
70+
assert(stream_c_locale<CharT>(std::chrono::local_time<std::chrono::microseconds>{-946'688'523'123'456us}) ==
71+
SV("1940-01-01 22:57:56.876544"));
72+
73+
assert(stream_c_locale<CharT>(std::chrono::local_time<std::chrono::milliseconds>{-946'688'523'123ms}) ==
74+
SV("1940-01-01 22:57:56.877"));
75+
76+
assert(stream_c_locale<CharT>(std::chrono::local_time<std::chrono::nanoseconds>{-1ns}) ==
77+
SV("1969-12-31 23:59:59.999999999"));
78+
79+
assert(stream_c_locale<CharT>(std::chrono::local_time<std::chrono::nanoseconds>{0ns}) ==
80+
SV("1970-01-01 00:00:00.000000000"));
81+
82+
assert(stream_c_locale<CharT>(std::chrono::local_time<std::chrono::nanoseconds>{1ns}) ==
83+
SV("1970-01-01 00:00:00.000000001"));
84+
6785
assert(stream_c_locale<CharT>(std::chrono::local_time<std::chrono::nanoseconds>{946'688'523'123'456'789ns}) ==
6886
SV("2000-01-01 01:02:03.123456789"));
6987
assert(stream_c_locale<CharT>(std::chrono::local_time<std::chrono::microseconds>{946'688'523'123'456us}) ==
@@ -97,6 +115,24 @@ template <class CharT>
97115
static void test_fr_FR() {
98116
using namespace std::literals::chrono_literals;
99117

118+
assert(stream_fr_FR_locale<CharT>(std::chrono::local_time<std::chrono::nanoseconds>{-946'688'523'123'456'789ns}) ==
119+
SV("1940-01-01 22:57:56,876543211"));
120+
121+
assert(stream_fr_FR_locale<CharT>(std::chrono::local_time<std::chrono::microseconds>{-946'688'523'123'456us}) ==
122+
SV("1940-01-01 22:57:56,876544"));
123+
124+
assert(stream_fr_FR_locale<CharT>(std::chrono::local_time<std::chrono::milliseconds>{-946'688'523'123ms}) ==
125+
SV("1940-01-01 22:57:56,877"));
126+
127+
assert(stream_fr_FR_locale<CharT>(std::chrono::local_time<std::chrono::nanoseconds>{-1ns}) ==
128+
SV("1969-12-31 23:59:59,999999999"));
129+
130+
assert(stream_fr_FR_locale<CharT>(std::chrono::local_time<std::chrono::nanoseconds>{0ns}) ==
131+
SV("1970-01-01 00:00:00,000000000"));
132+
133+
assert(stream_fr_FR_locale<CharT>(std::chrono::local_time<std::chrono::nanoseconds>{1ns}) ==
134+
SV("1970-01-01 00:00:00,000000001"));
135+
100136
assert(stream_fr_FR_locale<CharT>(std::chrono::local_time<std::chrono::nanoseconds>{946'688'523'123'456'789ns}) ==
101137
SV("2000-01-01 01:02:03,123456789"));
102138
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>
131167
static void test_ja_JP() {
132168
using namespace std::literals::chrono_literals;
133169

170+
assert(stream_ja_JP_locale<CharT>(std::chrono::local_time<std::chrono::nanoseconds>{-946'688'523'123'456'789ns}) ==
171+
SV("1940-01-01 22:57:56.876543211"));
172+
173+
assert(stream_ja_JP_locale<CharT>(std::chrono::local_time<std::chrono::microseconds>{-946'688'523'123'456us}) ==
174+
SV("1940-01-01 22:57:56.876544"));
175+
176+
assert(stream_ja_JP_locale<CharT>(std::chrono::local_time<std::chrono::milliseconds>{-946'688'523'123ms}) ==
177+
SV("1940-01-01 22:57:56.877"));
178+
179+
assert(stream_ja_JP_locale<CharT>(std::chrono::local_time<std::chrono::nanoseconds>{-1ns}) ==
180+
SV("1969-12-31 23:59:59.999999999"));
181+
182+
assert(stream_ja_JP_locale<CharT>(std::chrono::local_time<std::chrono::nanoseconds>{0ns}) ==
183+
SV("1970-01-01 00:00:00.000000000"));
184+
185+
assert(stream_ja_JP_locale<CharT>(std::chrono::local_time<std::chrono::nanoseconds>{1ns}) ==
186+
SV("1970-01-01 00:00:00.000000001"));
187+
134188
assert(stream_ja_JP_locale<CharT>(std::chrono::local_time<std::chrono::nanoseconds>{946'688'523'123'456'789ns}) ==
135189
SV("2000-01-01 01:02:03.123456789"));
136190
assert(stream_ja_JP_locale<CharT>(std::chrono::local_time<std::chrono::microseconds>{946'688'523'123'456us}) ==

libcxx/test/std/time/time.clock/time.clock.system/sys_time.ostream.pass.cpp

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,24 @@ template <class CharT>
6464
static void test_c() {
6565
using namespace std::literals::chrono_literals;
6666

67+
assert(stream_c_locale<CharT>(std::chrono::sys_time<std::chrono::nanoseconds>{-946'688'523'123'456'789ns}) ==
68+
SV("1940-01-01 22:57:56.876543211"));
69+
70+
assert(stream_c_locale<CharT>(std::chrono::sys_time<std::chrono::microseconds>{-946'688'523'123'456us}) ==
71+
SV("1940-01-01 22:57:56.876544"));
72+
73+
assert(stream_c_locale<CharT>(std::chrono::sys_time<std::chrono::milliseconds>{-946'688'523'123ms}) ==
74+
SV("1940-01-01 22:57:56.877"));
75+
76+
assert(stream_c_locale<CharT>(std::chrono::sys_time<std::chrono::nanoseconds>{-1ns}) ==
77+
SV("1969-12-31 23:59:59.999999999"));
78+
79+
assert(stream_c_locale<CharT>(std::chrono::sys_time<std::chrono::nanoseconds>{0ns}) ==
80+
SV("1970-01-01 00:00:00.000000000"));
81+
82+
assert(stream_c_locale<CharT>(std::chrono::sys_time<std::chrono::nanoseconds>{1ns}) ==
83+
SV("1970-01-01 00:00:00.000000001"));
84+
6785
assert(stream_c_locale<CharT>(std::chrono::sys_time<std::chrono::nanoseconds>{946'688'523'123'456'789ns}) ==
6886
SV("2000-01-01 01:02:03.123456789"));
6987
assert(stream_c_locale<CharT>(std::chrono::sys_time<std::chrono::microseconds>{946'688'523'123'456us}) ==
@@ -92,6 +110,24 @@ template <class CharT>
92110
static void test_fr_FR() {
93111
using namespace std::literals::chrono_literals;
94112

113+
assert(stream_fr_FR_locale<CharT>(std::chrono::sys_time<std::chrono::nanoseconds>{-946'688'523'123'456'789ns}) ==
114+
SV("1940-01-01 22:57:56,876543211"));
115+
116+
assert(stream_fr_FR_locale<CharT>(std::chrono::sys_time<std::chrono::microseconds>{-946'688'523'123'456us}) ==
117+
SV("1940-01-01 22:57:56,876544"));
118+
119+
assert(stream_fr_FR_locale<CharT>(std::chrono::sys_time<std::chrono::milliseconds>{-946'688'523'123ms}) ==
120+
SV("1940-01-01 22:57:56,877"));
121+
122+
assert(stream_fr_FR_locale<CharT>(std::chrono::sys_time<std::chrono::nanoseconds>{-1ns}) ==
123+
SV("1969-12-31 23:59:59,999999999"));
124+
125+
assert(stream_fr_FR_locale<CharT>(std::chrono::sys_time<std::chrono::nanoseconds>{0ns}) ==
126+
SV("1970-01-01 00:00:00,000000000"));
127+
128+
assert(stream_fr_FR_locale<CharT>(std::chrono::sys_time<std::chrono::nanoseconds>{1ns}) ==
129+
SV("1970-01-01 00:00:00,000000001"));
130+
95131
assert(stream_fr_FR_locale<CharT>(std::chrono::sys_time<std::chrono::nanoseconds>{946'688'523'123'456'789ns}) ==
96132
SV("2000-01-01 01:02:03,123456789"));
97133
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>
120156
static void test_ja_JP() {
121157
using namespace std::literals::chrono_literals;
122158

159+
assert(stream_ja_JP_locale<CharT>(std::chrono::sys_time<std::chrono::nanoseconds>{-946'688'523'123'456'789ns}) ==
160+
SV("1940-01-01 22:57:56.876543211"));
161+
162+
assert(stream_ja_JP_locale<CharT>(std::chrono::sys_time<std::chrono::microseconds>{-946'688'523'123'456us}) ==
163+
SV("1940-01-01 22:57:56.876544"));
164+
165+
assert(stream_ja_JP_locale<CharT>(std::chrono::sys_time<std::chrono::milliseconds>{-946'688'523'123ms}) ==
166+
SV("1940-01-01 22:57:56.877"));
167+
168+
assert(stream_ja_JP_locale<CharT>(std::chrono::sys_time<std::chrono::nanoseconds>{-1ns}) ==
169+
SV("1969-12-31 23:59:59.999999999"));
170+
171+
assert(stream_ja_JP_locale<CharT>(std::chrono::sys_time<std::chrono::nanoseconds>{0ns}) ==
172+
SV("1970-01-01 00:00:00.000000000"));
173+
174+
assert(stream_ja_JP_locale<CharT>(std::chrono::sys_time<std::chrono::nanoseconds>{1ns}) ==
175+
SV("1970-01-01 00:00:00.000000001"));
176+
123177
assert(stream_ja_JP_locale<CharT>(std::chrono::sys_time<std::chrono::nanoseconds>{946'688'523'123'456'789ns}) ==
124178
SV("2000-01-01 01:02:03.123456789"));
125179
assert(stream_ja_JP_locale<CharT>(std::chrono::sys_time<std::chrono::microseconds>{946'688'523'123'456us}) ==

0 commit comments

Comments
 (0)