Skip to content

[libc++][TZDB] Fixes mapping of nonexisting time. #127330

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
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions libcxx/include/__chrono/time_zone.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,10 +103,14 @@ class _LIBCPP_AVAILABILITY_TZDB time_zone {
to_sys(const local_time<_Duration>& __time, choose __z) const {
local_info __info = get_info(__time);
switch (__info.result) {
case local_info::unique:
case local_info::nonexistent: // first and second are the same
case local_info::unique: // first and second are the same
return sys_time<common_type_t<_Duration, seconds>>{__time.time_since_epoch() - __info.first.offset};

case local_info::nonexistent:
// first and second are the same
// All non-existing values are converted to the same time.
return sys_time<common_type_t<_Duration, seconds>>{__info.first.end};

case local_info::ambiguous:
switch (__z) {
case choose::earliest:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ static void test_nonexistent() {
// Pick an historic date where it's well known what the time zone rules were.
// This makes it unlikely updates to the database change these rules.
std::chrono::local_time<std::chrono::seconds> time{
(std::chrono::sys_days{std::chrono::March / 30 / 1986} + 2h + 30min).time_since_epoch()};
(std::chrono::sys_days{std::chrono::March / 30 / 1986} + 2h).time_since_epoch()};

std::chrono::sys_seconds expected{time.time_since_epoch() - 1h};

Expand All @@ -100,6 +100,13 @@ static void test_nonexistent() {
assert(tz->to_sys(time + 0us, std::chrono::choose::latest) == expected);
assert(tz->to_sys(time + 0ms, std::chrono::choose::earliest) == expected);
assert(tz->to_sys(time + 0s, std::chrono::choose::latest) == expected);

// The entire nonexisting hour should map to the same time.
// For nonexistant the value of std::chrono::choose has no effect.
assert(tz->to_sys(time + 1s, std::chrono::choose::earliest) == expected);
assert(tz->to_sys(time + 1min, std::chrono::choose::latest) == expected);
assert(tz->to_sys(time + 30min, std::chrono::choose::earliest) == expected);
assert(tz->to_sys(time + 59min + 59s, std::chrono::choose::latest) == expected);
}

// Tests ambiguous conversions.
Expand All @@ -120,7 +127,7 @@ static void test_ambiguous() {
// Pick an historic date where it's well known what the time zone rules were.
// This makes it unlikely updates to the database change these rules.
std::chrono::local_time<std::chrono::seconds> time{
(std::chrono::sys_days{std::chrono::September / 28 / 1986} + 2h + 30min).time_since_epoch()};
(std::chrono::sys_days{std::chrono::September / 28 / 1986} + 2h).time_since_epoch()};

std::chrono::sys_seconds earlier{time.time_since_epoch() - 2h};
std::chrono::sys_seconds later{time.time_since_epoch() - 1h};
Expand All @@ -133,6 +140,12 @@ static void test_ambiguous() {
assert(tz->to_sys(time + 0us, std::chrono::choose::latest) == later);
assert(tz->to_sys(time + 0ms, std::chrono::choose::earliest) == earlier);
assert(tz->to_sys(time + 0s, std::chrono::choose::latest) == later);

// Test times in the ambigious hour
assert(tz->to_sys(time + 1s, std::chrono::choose::earliest) == earlier + 1s);
assert(tz->to_sys(time + 1min, std::chrono::choose::latest) == later + 1min);
assert(tz->to_sys(time + 30min, std::chrono::choose::earliest) == earlier + 30min);
assert(tz->to_sys(time + 59min + 59s, std::chrono::choose::latest) == later + 59min + 59s);
}

// This test does the basic validations of this function. The library function
Expand Down