[libc++][TZDB] Fixes mapping of nonexisting time. (#127330)
All non-existing local times in a contiguous range should map to the same time point. This fixes a bug, were the times inside the range were mapped to the wrong time. Fixes: #113654
This commit is contained in:
parent
74656476b8
commit
941f7cbf5a
@ -103,10 +103,14 @@ public:
|
||||
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:
|
||||
|
||||
@ -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};
|
||||
|
||||
@ -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.
|
||||
@ -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};
|
||||
@ -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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user