Skip to content

Commit d094cde

Browse files
committed
[libc++][chrono] Fixes leap seconds.
While implementing the UTC clock it turns out that the implementation of the leap seconds was not correct, it should store the individual value, not the sum. It also looks like LWG3359 has not been fully implemented. Implements parts of: - LWG3359 <chrono> leap second support should allow for negative leap seconds
1 parent 6939905 commit d094cde

File tree

4 files changed

+83
-61
lines changed

4 files changed

+83
-61
lines changed

Diff for: libcxx/docs/Status/Cxx20Issues.csv

+1-1
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@
269269
"`3355 <https://wg21.link/LWG3355>`__","The memory algorithms should support move-only input iterators introduced by P1207","Prague","|Complete|","15.0","|ranges|"
270270
"`3356 <https://wg21.link/LWG3356>`__","``__cpp_lib_nothrow_convertible``\ should be ``__cpp_lib_is_nothrow_convertible``\ ","Prague","|Complete|","12.0"
271271
"`3358 <https://wg21.link/LWG3358>`__","|sect|\ [span.cons] is mistaken that ``to_address``\ can throw","Prague","|Complete|","17.0"
272-
"`3359 <https://wg21.link/LWG3359>`__","``<chrono>``\ leap second support should allow for negative leap seconds","Prague","|Complete|","19.0","|chrono|"
272+
"`3359 <https://wg21.link/LWG3359>`__","``<chrono>``\ leap second support should allow for negative leap seconds","Prague","|In Progress|","","|chrono|"
273273
"`3360 <https://wg21.link/LWG3360>`__","``three_way_comparable_with``\ is inconsistent with similar concepts","Prague","|Nothing To Do|","","|spaceship|"
274274
"`3362 <https://wg21.link/LWG3362>`__","Strike ``stop_source``\ 's ``operator!=``\ ","Prague","",""
275275
"`3363 <https://wg21.link/LWG3363>`__","``drop_while_view``\ should opt-out of ``sized_range``\ ","Prague","|Nothing To Do|","","|ranges|"

Diff for: libcxx/src/tzdb.cpp

+40-24
Original file line numberDiff line numberDiff line change
@@ -626,29 +626,49 @@ static void __parse_leap_seconds(vector<leap_second>& __leap_seconds, istream&&
626626
// seconds since 1 January 1970.
627627
constexpr auto __offset = sys_days{1970y / January / 1} - sys_days{1900y / January / 1};
628628

629-
while (true) {
630-
switch (__input.peek()) {
631-
case istream::traits_type::eof():
632-
return;
633-
634-
case ' ':
635-
case '\t':
636-
case '\n':
637-
__input.get();
638-
continue;
629+
struct __entry {
630+
sys_seconds __timestamp;
631+
seconds __value;
632+
};
633+
vector<__entry> __entries;
634+
[&] {
635+
while (true) {
636+
switch (__input.peek()) {
637+
case istream::traits_type::eof():
638+
return;
639+
640+
case ' ':
641+
case '\t':
642+
case '\n':
643+
__input.get();
644+
continue;
645+
646+
case '#':
647+
chrono::__skip_line(__input);
648+
continue;
649+
}
639650

640-
case '#':
651+
sys_seconds __date = sys_seconds{seconds{chrono::__parse_integral(__input, false)}} - __offset;
652+
chrono::__skip_mandatory_whitespace(__input);
653+
seconds __value{chrono::__parse_integral(__input, false)};
641654
chrono::__skip_line(__input);
642-
continue;
643-
}
644655

645-
sys_seconds __date = sys_seconds{seconds{chrono::__parse_integral(__input, false)}} - __offset;
646-
chrono::__skip_mandatory_whitespace(__input);
647-
seconds __value{chrono::__parse_integral(__input, false)};
648-
chrono::__skip_line(__input);
649-
650-
__leap_seconds.emplace_back(std::__private_constructor_tag{}, __date, __value);
651-
}
656+
__entries.emplace_back(__date, __value);
657+
}
658+
}();
659+
// The Standard requires the leap seconds to be sorted. The file
660+
// leap-seconds.list usually provides them in sorted order, but that is not
661+
// guaranteed so we ensure it here.
662+
std::ranges::sort(__entries, {}, &__entry::__timestamp);
663+
664+
// The database should contain the number of seconds inserted by a leap
665+
// second (1 or -1). So the difference between the two elements are stored.
666+
// std::ranges::views::adjacent has not been implemented yet.
667+
(void)ranges::adjacent_find(__entries, [&](const __entry& __first, const __entry& __second) {
668+
__leap_seconds.emplace_back(
669+
std::__private_constructor_tag{}, __second.__timestamp, __second.__value - __first.__value);
670+
return false;
671+
});
652672
}
653673

654674
void __init_tzdb(tzdb& __tzdb, __tz::__rules_storage_type& __rules) {
@@ -667,10 +687,6 @@ void __init_tzdb(tzdb& __tzdb, __tz::__rules_storage_type& __rules) {
667687
// The latter is much easier to parse, it seems Howard shares that
668688
// opinion.
669689
chrono::__parse_leap_seconds(__tzdb.leap_seconds, ifstream{__root / "leap-seconds.list"});
670-
// The Standard requires the leap seconds to be sorted. The file
671-
// leap-seconds.list usually provides them in sorted order, but that is not
672-
// guaranteed so we ensure it here.
673-
std::ranges::sort(__tzdb.leap_seconds);
674690
}
675691

676692
#ifdef _WIN32

Diff for: libcxx/test/libcxx/time/time.zone/time.zone.db/leap_seconds.pass.cpp

+15-8
Original file line numberDiff line numberDiff line change
@@ -83,32 +83,39 @@ static void test_leap_seconds() {
8383
2303683200 12 # 1 Jan 1973
8484
2287785600 11 # 1 Jul 1972
8585
2272060800 10 # 1 Jan 1972
86-
86400 1 # 2 Jan 1900 Dummy entry to test before 1970
86+
86400 9 # 2 Jan 1900 Dummy entry to test before 1970
87+
1 8 # 2 Jan 1900 Dummy entry to test before 1970
88+
89+
# Fictional negative leap second
90+
2303769600 11 # 2 Jan 1973
8791
8892
# largest accepted value by the parser
89-
5764607523034234879 2
93+
5764607523034234879 12
9094
)");
9195

92-
assert(result.leap_seconds.size() == 5);
96+
assert(result.leap_seconds.size() == 6);
9397

9498
assert(result.leap_seconds[0].date() == sys_seconds{sys_days{1900y / January / 2}});
9599
assert(result.leap_seconds[0].value() == 1s);
96100

97101
assert(result.leap_seconds[1].date() == sys_seconds{sys_days{1972y / January / 1}});
98-
assert(result.leap_seconds[1].value() == 10s);
102+
assert(result.leap_seconds[1].value() == 1s);
99103

100104
assert(result.leap_seconds[2].date() == sys_seconds{sys_days{1972y / July / 1}});
101-
assert(result.leap_seconds[2].value() == 11s);
105+
assert(result.leap_seconds[2].value() == 1s);
102106

103107
assert(result.leap_seconds[3].date() == sys_seconds{sys_days{1973y / January / 1}});
104-
assert(result.leap_seconds[3].value() == 12s);
108+
assert(result.leap_seconds[3].value() == 1s);
109+
110+
assert(result.leap_seconds[4].date() == sys_seconds{sys_days{1973y / January / 2}});
111+
assert(result.leap_seconds[4].value() == -1s);
105112

106-
assert(result.leap_seconds[4].date() ==
113+
assert(result.leap_seconds[5].date() ==
107114
sys_seconds{5764607523034234879s
108115
// The database uses 1900-01-01 as epoch.
109116
- std::chrono::duration_cast<std::chrono::seconds>(
110117
sys_days{1970y / January / 1} - sys_days{1900y / January / 1})});
111-
assert(result.leap_seconds[4].value() == 2s);
118+
assert(result.leap_seconds[5].value() == 1s);
112119
}
113120

114121
int main(int, const char**) {

Diff for: libcxx/test/std/time/time.zone/time.zone.db/leap_seconds.pass.cpp

+27-28
Original file line numberDiff line numberDiff line change
@@ -33,34 +33,33 @@ using namespace std::literals::chrono_literals;
3333
// At the moment of writing that list is the actual list in the IANA database.
3434
// If in the future more leap seconds can be added.
3535
static const std::array leap_seconds = {
36-
std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1972y / std::chrono::January / 1}}, 10s),
37-
std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1972y / std::chrono::July / 1}}, 11s),
38-
std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1973y / std::chrono::January / 1}}, 12s),
39-
std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1974y / std::chrono::January / 1}}, 13s),
40-
std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1975y / std::chrono::January / 1}}, 14s),
41-
std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1976y / std::chrono::January / 1}}, 15s),
42-
std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1977y / std::chrono::January / 1}}, 16s),
43-
std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1978y / std::chrono::January / 1}}, 17s),
44-
std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1979y / std::chrono::January / 1}}, 18s),
45-
std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1980y / std::chrono::January / 1}}, 19s),
46-
std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1981y / std::chrono::July / 1}}, 20s),
47-
std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1982y / std::chrono::July / 1}}, 21s),
48-
std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1983y / std::chrono::July / 1}}, 22s),
49-
std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1985y / std::chrono::July / 1}}, 23s),
50-
std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1988y / std::chrono::January / 1}}, 24s),
51-
std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1990y / std::chrono::January / 1}}, 25s),
52-
std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1991y / std::chrono::January / 1}}, 26s),
53-
std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1992y / std::chrono::July / 1}}, 27s),
54-
std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1993y / std::chrono::July / 1}}, 28s),
55-
std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1994y / std::chrono::July / 1}}, 29s),
56-
std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1996y / std::chrono::January / 1}}, 30s),
57-
std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1997y / std::chrono::July / 1}}, 31s),
58-
std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1999y / std::chrono::January / 1}}, 32s),
59-
std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{2006y / std::chrono::January / 1}}, 33s),
60-
std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{2009y / std::chrono::January / 1}}, 34s),
61-
std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{2012y / std::chrono::July / 1}}, 35s),
62-
std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{2015y / std::chrono::July / 1}}, 36s),
63-
std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{2017y / std::chrono::January / 1}}, 37s)};
36+
std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1972y / std::chrono::July / 1}}, 1s),
37+
std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1973y / std::chrono::January / 1}}, 1s),
38+
std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1974y / std::chrono::January / 1}}, 1s),
39+
std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1975y / std::chrono::January / 1}}, 1s),
40+
std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1976y / std::chrono::January / 1}}, 1s),
41+
std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1977y / std::chrono::January / 1}}, 1s),
42+
std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1978y / std::chrono::January / 1}}, 1s),
43+
std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1979y / std::chrono::January / 1}}, 1s),
44+
std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1980y / std::chrono::January / 1}}, 1s),
45+
std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1981y / std::chrono::July / 1}}, 1s),
46+
std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1982y / std::chrono::July / 1}}, 1s),
47+
std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1983y / std::chrono::July / 1}}, 1s),
48+
std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1985y / std::chrono::July / 1}}, 1s),
49+
std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1988y / std::chrono::January / 1}}, 1s),
50+
std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1990y / std::chrono::January / 1}}, 1s),
51+
std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1991y / std::chrono::January / 1}}, 1s),
52+
std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1992y / std::chrono::July / 1}}, 1s),
53+
std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1993y / std::chrono::July / 1}}, 1s),
54+
std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1994y / std::chrono::July / 1}}, 1s),
55+
std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1996y / std::chrono::January / 1}}, 1s),
56+
std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1997y / std::chrono::July / 1}}, 1s),
57+
std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1999y / std::chrono::January / 1}}, 1s),
58+
std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{2006y / std::chrono::January / 1}}, 1s),
59+
std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{2009y / std::chrono::January / 1}}, 1s),
60+
std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{2012y / std::chrono::July / 1}}, 1s),
61+
std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{2015y / std::chrono::July / 1}}, 1s),
62+
std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{2017y / std::chrono::January / 1}}, 1s)};
6463

6564
int main(int, const char**) {
6665
const std::chrono::tzdb& tzdb = std::chrono::get_tzdb();

0 commit comments

Comments
 (0)