diff --git a/libcxx/docs/Status/Cxx20Issues.csv b/libcxx/docs/Status/Cxx20Issues.csv index e748ff6ad749b..f617ffd13315d 100644 --- a/libcxx/docs/Status/Cxx20Issues.csv +++ b/libcxx/docs/Status/Cxx20Issues.csv @@ -269,7 +269,7 @@ "`3355 `__","The memory algorithms should support move-only input iterators introduced by P1207","Prague","|Complete|","15.0","|ranges|" "`3356 `__","``__cpp_lib_nothrow_convertible``\ should be ``__cpp_lib_is_nothrow_convertible``\ ","Prague","|Complete|","12.0" "`3358 `__","|sect|\ [span.cons] is mistaken that ``to_address``\ can throw","Prague","|Complete|","17.0" -"`3359 `__","````\ leap second support should allow for negative leap seconds","Prague","|Complete|","19.0","|chrono|" +"`3359 `__","````\ leap second support should allow for negative leap seconds","Prague","|In Progress|","","|chrono|" "`3360 `__","``three_way_comparable_with``\ is inconsistent with similar concepts","Prague","|Nothing To Do|","","|spaceship|" "`3362 `__","Strike ``stop_source``\ 's ``operator!=``\ ","Prague","","" "`3363 `__","``drop_while_view``\ should opt-out of ``sized_range``\ ","Prague","|Nothing To Do|","","|ranges|" diff --git a/libcxx/src/tzdb.cpp b/libcxx/src/tzdb.cpp index 5951e59248e94..2d07796c6951f 100644 --- a/libcxx/src/tzdb.cpp +++ b/libcxx/src/tzdb.cpp @@ -626,29 +626,49 @@ static void __parse_leap_seconds(vector& __leap_seconds, istream&& // seconds since 1 January 1970. constexpr auto __offset = sys_days{1970y / January / 1} - sys_days{1900y / January / 1}; - while (true) { - switch (__input.peek()) { - case istream::traits_type::eof(): - return; - - case ' ': - case '\t': - case '\n': - __input.get(); - continue; + struct __entry { + sys_seconds __timestamp; + seconds __value; + }; + vector<__entry> __entries; + [&] { + while (true) { + switch (__input.peek()) { + case istream::traits_type::eof(): + return; + + case ' ': + case '\t': + case '\n': + __input.get(); + continue; + + case '#': + chrono::__skip_line(__input); + continue; + } - case '#': + sys_seconds __date = sys_seconds{seconds{chrono::__parse_integral(__input, false)}} - __offset; + chrono::__skip_mandatory_whitespace(__input); + seconds __value{chrono::__parse_integral(__input, false)}; chrono::__skip_line(__input); - continue; - } - sys_seconds __date = sys_seconds{seconds{chrono::__parse_integral(__input, false)}} - __offset; - chrono::__skip_mandatory_whitespace(__input); - seconds __value{chrono::__parse_integral(__input, false)}; - chrono::__skip_line(__input); - - __leap_seconds.emplace_back(std::__private_constructor_tag{}, __date, __value); - } + __entries.emplace_back(__date, __value); + } + }(); + // The Standard requires the leap seconds to be sorted. The file + // leap-seconds.list usually provides them in sorted order, but that is not + // guaranteed so we ensure it here. + ranges::sort(__entries, {}, &__entry::__timestamp); + + // The database should contain the number of seconds inserted by a leap + // second (1 or -1). So the difference between the two elements is stored. + // std::ranges::views::adjacent has not been implemented yet. + (void)ranges::adjacent_find(__entries, [&](const __entry& __first, const __entry& __second) { + __leap_seconds.emplace_back( + std::__private_constructor_tag{}, __second.__timestamp, __second.__value - __first.__value); + return false; + }); } void __init_tzdb(tzdb& __tzdb, __tz::__rules_storage_type& __rules) { @@ -667,10 +687,6 @@ void __init_tzdb(tzdb& __tzdb, __tz::__rules_storage_type& __rules) { // The latter is much easier to parse, it seems Howard shares that // opinion. chrono::__parse_leap_seconds(__tzdb.leap_seconds, ifstream{__root / "leap-seconds.list"}); - // The Standard requires the leap seconds to be sorted. The file - // leap-seconds.list usually provides them in sorted order, but that is not - // guaranteed so we ensure it here. - std::ranges::sort(__tzdb.leap_seconds); } #ifdef _WIN32 diff --git a/libcxx/test/libcxx/time/time.zone/time.zone.db/leap_seconds.pass.cpp b/libcxx/test/libcxx/time/time.zone/time.zone.db/leap_seconds.pass.cpp index 25a0f00003da2..d7ae21926b4b2 100644 --- a/libcxx/test/libcxx/time/time.zone/time.zone.db/leap_seconds.pass.cpp +++ b/libcxx/test/libcxx/time/time.zone/time.zone.db/leap_seconds.pass.cpp @@ -83,32 +83,39 @@ static void test_leap_seconds() { 2303683200 12 # 1 Jan 1973 2287785600 11 # 1 Jul 1972 2272060800 10 # 1 Jan 1972 -86400 1 # 2 Jan 1900 Dummy entry to test before 1970 +86400 9 # 2 Jan 1900 Dummy entry to test before 1970 +1 8 # 2 Jan 1900 Dummy entry to test before 1970 + +# Fictional negative leap second +2303769600 11 # 2 Jan 1973 # largest accepted value by the parser -5764607523034234879 2 +5764607523034234879 12 )"); - assert(result.leap_seconds.size() == 5); + assert(result.leap_seconds.size() == 6); assert(result.leap_seconds[0].date() == sys_seconds{sys_days{1900y / January / 2}}); assert(result.leap_seconds[0].value() == 1s); assert(result.leap_seconds[1].date() == sys_seconds{sys_days{1972y / January / 1}}); - assert(result.leap_seconds[1].value() == 10s); + assert(result.leap_seconds[1].value() == 1s); assert(result.leap_seconds[2].date() == sys_seconds{sys_days{1972y / July / 1}}); - assert(result.leap_seconds[2].value() == 11s); + assert(result.leap_seconds[2].value() == 1s); assert(result.leap_seconds[3].date() == sys_seconds{sys_days{1973y / January / 1}}); - assert(result.leap_seconds[3].value() == 12s); + assert(result.leap_seconds[3].value() == 1s); + + assert(result.leap_seconds[4].date() == sys_seconds{sys_days{1973y / January / 2}}); + assert(result.leap_seconds[4].value() == -1s); - assert(result.leap_seconds[4].date() == + assert(result.leap_seconds[5].date() == sys_seconds{5764607523034234879s // The database uses 1900-01-01 as epoch. - std::chrono::duration_cast( sys_days{1970y / January / 1} - sys_days{1900y / January / 1})}); - assert(result.leap_seconds[4].value() == 2s); + assert(result.leap_seconds[5].value() == 1s); } int main(int, const char**) { diff --git a/libcxx/test/std/time/time.zone/time.zone.db/leap_seconds.pass.cpp b/libcxx/test/std/time/time.zone/time.zone.db/leap_seconds.pass.cpp index f873ad3167819..39023c31aecbb 100644 --- a/libcxx/test/std/time/time.zone/time.zone.db/leap_seconds.pass.cpp +++ b/libcxx/test/std/time/time.zone/time.zone.db/leap_seconds.pass.cpp @@ -33,34 +33,33 @@ using namespace std::literals::chrono_literals; // At the moment of writing that list is the actual list in the IANA database. // If in the future more leap seconds can be added. static const std::array leap_seconds = { - std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1972y / std::chrono::January / 1}}, 10s), - std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1972y / std::chrono::July / 1}}, 11s), - std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1973y / std::chrono::January / 1}}, 12s), - std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1974y / std::chrono::January / 1}}, 13s), - std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1975y / std::chrono::January / 1}}, 14s), - std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1976y / std::chrono::January / 1}}, 15s), - std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1977y / std::chrono::January / 1}}, 16s), - std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1978y / std::chrono::January / 1}}, 17s), - std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1979y / std::chrono::January / 1}}, 18s), - std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1980y / std::chrono::January / 1}}, 19s), - std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1981y / std::chrono::July / 1}}, 20s), - std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1982y / std::chrono::July / 1}}, 21s), - std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1983y / std::chrono::July / 1}}, 22s), - std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1985y / std::chrono::July / 1}}, 23s), - std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1988y / std::chrono::January / 1}}, 24s), - std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1990y / std::chrono::January / 1}}, 25s), - std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1991y / std::chrono::January / 1}}, 26s), - std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1992y / std::chrono::July / 1}}, 27s), - std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1993y / std::chrono::July / 1}}, 28s), - std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1994y / std::chrono::July / 1}}, 29s), - std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1996y / std::chrono::January / 1}}, 30s), - std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1997y / std::chrono::July / 1}}, 31s), - std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1999y / std::chrono::January / 1}}, 32s), - std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{2006y / std::chrono::January / 1}}, 33s), - std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{2009y / std::chrono::January / 1}}, 34s), - std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{2012y / std::chrono::July / 1}}, 35s), - std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{2015y / std::chrono::July / 1}}, 36s), - std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{2017y / std::chrono::January / 1}}, 37s)}; + std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1972y / std::chrono::July / 1}}, 1s), + std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1973y / std::chrono::January / 1}}, 1s), + std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1974y / std::chrono::January / 1}}, 1s), + std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1975y / std::chrono::January / 1}}, 1s), + std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1976y / std::chrono::January / 1}}, 1s), + std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1977y / std::chrono::January / 1}}, 1s), + std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1978y / std::chrono::January / 1}}, 1s), + std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1979y / std::chrono::January / 1}}, 1s), + std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1980y / std::chrono::January / 1}}, 1s), + std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1981y / std::chrono::July / 1}}, 1s), + std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1982y / std::chrono::July / 1}}, 1s), + std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1983y / std::chrono::July / 1}}, 1s), + std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1985y / std::chrono::July / 1}}, 1s), + std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1988y / std::chrono::January / 1}}, 1s), + std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1990y / std::chrono::January / 1}}, 1s), + std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1991y / std::chrono::January / 1}}, 1s), + std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1992y / std::chrono::July / 1}}, 1s), + std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1993y / std::chrono::July / 1}}, 1s), + std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1994y / std::chrono::July / 1}}, 1s), + std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1996y / std::chrono::January / 1}}, 1s), + std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1997y / std::chrono::July / 1}}, 1s), + std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{1999y / std::chrono::January / 1}}, 1s), + std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{2006y / std::chrono::January / 1}}, 1s), + std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{2009y / std::chrono::January / 1}}, 1s), + std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{2012y / std::chrono::July / 1}}, 1s), + std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{2015y / std::chrono::July / 1}}, 1s), + std::make_pair(std::chrono::sys_seconds{std::chrono::sys_days{2017y / std::chrono::January / 1}}, 1s)}; int main(int, const char**) { const std::chrono::tzdb& tzdb = std::chrono::get_tzdb();