Skip to content

Commit 957fca1

Browse files
committed
WIP: Try using the binary tzdb unconditionally on all platforms
1 parent ecef594 commit 957fca1

File tree

2 files changed

+10
-121
lines changed

2 files changed

+10
-121
lines changed

libcxx/src/experimental/tzdb.cpp

Lines changed: 6 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -633,7 +633,8 @@ static void __parse_tzdata(tzdb& __db, __tz::__rules_storage_type& __rules, istr
633633
}
634634

635635
// This function parses the leap-seconds "binary file" compiled from the .list file
636-
// by the zic compiler. That format is what's provided on some platforms like Darwin.
636+
// by the zic compiler. That format is widely available as it comes by default with
637+
// the IANA Time Zone Database.
637638
//
638639
// The format looks like:
639640
//
@@ -642,8 +643,7 @@ static void __parse_tzdata(tzdb& __db, __tz::__rules_storage_type& __rules, istr
642643
// Leap 1972 Dec 31 23:59:60 + S
643644
// Leap 1973 Dec 31 23:59:60 + S
644645
//
645-
inline vector<leap_second> __parse_leap_seconds_binary(istream&& __input) {
646-
vector<leap_second> __result;
646+
static void __parse_leap_seconds(vector<leap_second>& __leap_seconds, istream&& __input) {
647647
[&] {
648648
while (true) {
649649
switch (__input.peek()) {
@@ -699,86 +699,12 @@ inline vector<leap_second> __parse_leap_seconds_binary(istream&& __input) {
699699

700700
chrono::__skip_line(__input);
701701

702-
__result.emplace_back(std::__private_constructor_tag{}, __timestamp, __value);
702+
__leap_seconds.emplace_back(std::__private_constructor_tag{}, __timestamp, __value);
703703
}
704704
}();
705705

706706
// Ensure the leap seconds are sorted properly.
707-
ranges::sort(__result, {}, &leap_second::date);
708-
709-
return __result;
710-
}
711-
712-
// This function parses leap-seconds.list file as can be found at
713-
// https://hpiers.obspm.fr/iers/bul/bulc/ntp/leap-seconds.list
714-
//
715-
// The format looks like
716-
//
717-
// #NTP Time DTAI Day Month Year
718-
// #
719-
// 2272060800 10 # 1 Jan 1972
720-
// 2287785600 11 # 1 Jul 1972
721-
// 2303683200 12 # 1 Jan 1973
722-
//
723-
// Where the timestamps are expressed as a number of seconds since 1 January 1900, 00:00:00.
724-
inline vector<leap_second> __parse_leap_seconds_list(istream&& __input) {
725-
// The file stores dates since 1 January 1900, 00:00:00, we want
726-
// seconds since 1 January 1970.
727-
constexpr auto __offset = sys_days{1970y / January / 1} - sys_days{1900y / January / 1};
728-
729-
struct __entry {
730-
sys_seconds __timestamp;
731-
seconds __value;
732-
};
733-
vector<__entry> __entries;
734-
[&] {
735-
while (true) {
736-
switch (__input.peek()) {
737-
case istream::traits_type::eof():
738-
return;
739-
740-
case ' ':
741-
case '\t':
742-
case '\n':
743-
__input.get();
744-
continue;
745-
746-
case '#':
747-
chrono::__skip_line(__input);
748-
continue;
749-
}
750-
751-
sys_seconds __date = sys_seconds{seconds{chrono::__parse_integral(__input, false)}} - __offset;
752-
chrono::__skip_mandatory_whitespace(__input);
753-
seconds __value{chrono::__parse_integral(__input, false)};
754-
chrono::__skip_line(__input);
755-
756-
__entries.emplace_back(__date, __value);
757-
}
758-
}();
759-
// The Standard requires the leap seconds to be sorted. The file
760-
// leap-seconds.list usually provides them in sorted order, but that is not
761-
// guaranteed so we ensure it here.
762-
ranges::sort(__entries, {}, &__entry::__timestamp);
763-
764-
// The database should contain the number of seconds inserted by a leap
765-
// second (1 or -1). So the difference between the two elements is stored.
766-
// std::ranges::views::adjacent has not been implemented yet.
767-
vector<leap_second> __result;
768-
(void)ranges::adjacent_find(__entries, [&](const __entry& __first, const __entry& __second) {
769-
__result.emplace_back(std::__private_constructor_tag{}, __second.__timestamp, __second.__value - __first.__value);
770-
return false;
771-
});
772-
return __result;
773-
}
774-
775-
// Parse leap seconds from the appropriate location based on the platform.
776-
static void __parse_leap_seconds(vector<leap_second>& __leap_seconds, filesystem::path const& __tzdb_directory) {
777-
#if defined(__APPLE__)
778-
__leap_seconds.append_range(chrono::__parse_leap_seconds_binary(ifstream{__tzdb_directory / "leapseconds"}));
779-
#else
780-
__leap_seconds.append_range(chrono::__parse_leap_seconds_list(ifstream{__tzdb_directory / "leap-seconds.list"}));
781-
#endif
707+
ranges::sort(__leap_seconds, {}, &leap_second::date);
782708
}
783709

784710
void __init_tzdb(tzdb& __tzdb, __tz::__rules_storage_type& __rules) {
@@ -790,7 +716,7 @@ void __init_tzdb(tzdb& __tzdb, __tz::__rules_storage_type& __rules) {
790716
ranges::sort(__tzdb.zones);
791717
ranges::sort(__tzdb.links);
792718
ranges::sort(__rules, {}, [](const auto& p) { return p.first; });
793-
chrono::__parse_leap_seconds(__tzdb.leap_seconds, __root);
719+
chrono::__parse_leap_seconds(__tzdb.leap_seconds, ifstream{__root / "leapseconds"});
794720
}
795721

796722
#ifdef _WIN32

libcxx/test/libcxx/time/time.zone/time.zone.db/leap_seconds.pass.cpp

Lines changed: 4 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -28,20 +28,10 @@
2828
#include "filesystem_test_helper.h"
2929
#include "test_tzdb.h"
3030

31-
#if defined(__APPLE__)
32-
# define TEST_USE_BINARY_LEAP_SECONDS
33-
#else
34-
# define TEST_USE_LIST_LEAP_SECONDS
35-
#endif
36-
3731
scoped_test_env env;
3832
[[maybe_unused]] const std::filesystem::path dir = env.create_dir("zoneinfo");
3933
const std::filesystem::path tzdata = env.create_file("zoneinfo/tzdata.zi");
40-
#ifdef TEST_USE_BINARY_LEAP_SECONDS
41-
const std::filesystem::path leap_seconds = env.create_file("zoneinfo/leapseconds");
42-
#else
43-
const std::filesystem::path leap_seconds = env.create_file("zoneinfo/leap-seconds.list");
44-
#endif
34+
const std::filesystem::path leap_seconds = env.create_file("zoneinfo/leapseconds");
4535

4636
std::string_view std::chrono::__libcpp_tzdb_directory() {
4737
static std::string result = dir.string();
@@ -75,37 +65,17 @@ static void test_exception(std::string_view input, [[maybe_unused]] std::string_
7565
}
7666

7767
static void test_invalid() {
78-
#ifdef TEST_USE_BINARY_LEAP_SECONDS
7968
test_exception("0", "corrupt tzdb: expected character 'l' from string 'leap', got '0' instead");
8069
test_exception("Leap x", "corrupt tzdb: expected a digit");
8170
test_exception("Leap 1970 J", "corrupt tzdb month: invalid name");
8271
test_exception("Leap 1970 Jan 1 23:59:60 x", "corrupt tzdb: invalid leap second sign x");
83-
#else
84-
test_exception("0", "corrupt tzdb: expected a non-zero digit");
85-
test_exception("1", "corrupt tzdb: expected whitespace");
86-
test_exception("1 ", "corrupt tzdb: expected a non-zero digit");
87-
test_exception("5764607523034234880 2", "corrupt tzdb: integral too large");
88-
#endif
8972
}
9073

9174
static void test_leap_seconds() {
9275
using namespace std::chrono;
9376

94-
std::string list_format = R"(
95-
2303683200 12 # 1 Jan 1973
96-
2287785600 11 # 1 Jul 1972
97-
2272060800 10 # 1 Jan 1972
98-
86400 9 # 2 Jan 1900 Dummy entry to test before 1970
99-
1 8 # 2 Jan 1900 Dummy entry to test before 1970
100-
101-
# Fictional negative leap second
102-
2303769600 11 # 2 Jan 1973
103-
104-
# largest accepted value by the parser
105-
5764607523034234879 12
106-
)";
107-
108-
std::string binary_format = R"(
77+
// Test whether loading also sorts the entries in the proper order.
78+
const tzdb& result = parse(R"(
10979
Leap 1973 Jan 1 23:59:60 + S
11080
Leap 1972 Jul 1 23:59:60 + S
11181
Leap 1972 Jan 1 23:59:60 + S
@@ -114,14 +84,7 @@ Leap 1900 Jan 2 00:00:01 + S # 2 Jan 1900 Dummy entry to test before
11484
11585
Leap 1973 Jan 2 23:59:60 - S # Fictional negative leap second
11686
Leap 32767 Jan 1 23:59:60 + S # Largest year accepted by the parser
117-
)";
118-
119-
// Test whether loading also sorts the entries in the proper order.
120-
#ifdef TEST_USE_BINARY_LEAP_SECONDS
121-
const tzdb& result = parse(binary_format);
122-
#else
123-
const tzdb& result = parse(list_format);
124-
#endif
87+
)");
12588

12689
assert(result.leap_seconds.size() == 6);
12790

0 commit comments

Comments
 (0)