forked from llvm/llvm-project
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[libc++][TZDB] Implements time_zone::to_sys. (llvm#90901)
This implements the overload with the choose argument and adds this enum. Implements parts of: - P0355 Extending chrono to Calendars and Time Zones
- Loading branch information
Showing
7 changed files
with
264 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
37 changes: 37 additions & 0 deletions
37
libcxx/test/libcxx/time/time.zone/time.zone.timezone/choose.pass.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
// See https://llvm.org/LICENSE.txt for license information. | ||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
// UNSUPPORTED: c++03, c++11, c++14, c++17 | ||
// UNSUPPORTED: no-filesystem, no-localization, no-tzdb | ||
|
||
// XFAIL: libcpp-has-no-experimental-tzdb | ||
// XFAIL: availability-tzdb-missing | ||
|
||
// <chrono> | ||
|
||
// enum class choose; | ||
|
||
#include <chrono> | ||
#include <type_traits> | ||
#include <cassert> | ||
|
||
#include "test_macros.h" | ||
|
||
int main(int, char**) { | ||
using E = std::chrono::choose; | ||
static_assert(std::is_enum_v<E>); | ||
|
||
// Check that E is a scoped enum by checking for conversions. | ||
using UT = std::underlying_type_t<E>; | ||
static_assert(!std::is_convertible_v<E, UT>); | ||
|
||
[[maybe_unused]] const E& early = E::earliest; | ||
[[maybe_unused]] const E& late = E::latest; | ||
|
||
return 0; | ||
} |
41 changes: 41 additions & 0 deletions
41
.../libcxx/time/time.zone/time.zone.timezone/time.zone.members/assert.to_sys_choose.pass.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
// See https://llvm.org/LICENSE.txt for license information. | ||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
// UNSUPPORTED: c++03, c++11, c++14, c++17 | ||
|
||
// REQUIRES: has-unix-headers | ||
// REQUIRES: libcpp-hardening-mode={{extensive|debug}} | ||
// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing | ||
|
||
// XFAIL: libcpp-has-no-experimental-tzdb | ||
|
||
// <chrono> | ||
|
||
// template <class _Duration> | ||
// sys_time<common_type_t<Duration, seconds>> | ||
// to_sys(const local_time<Duration>& tp, choose z) const; | ||
|
||
#include <chrono> | ||
|
||
#include "check_assertion.h" | ||
|
||
// Tests values that cannot be converted. To make sure the test is does not depend on changes | ||
// in the database it uses a time zone with a fixed offset. | ||
int main(int, char**) { | ||
TEST_LIBCPP_ASSERT_FAILURE( | ||
std::chrono::locate_zone("Etc/GMT-1")->to_sys(std::chrono::local_seconds::min(), std::chrono::choose::earliest), | ||
"cannot convert the local time; it would be before the minimum system clock value"); | ||
|
||
// TODO TZDB look why std::chrono::local_seconds::max() fails | ||
TEST_LIBCPP_ASSERT_FAILURE( | ||
std::chrono::locate_zone("Etc/GMT+1") | ||
->to_sys(std::chrono::local_seconds::max() - std::chrono::seconds(1), std::chrono::choose::latest), | ||
"cannot convert the local time; it would be after the maximum system clock value"); | ||
|
||
return 0; | ||
} |
147 changes: 147 additions & 0 deletions
147
libcxx/test/std/time/time.zone/time.zone.timezone/time.zone.members/to_sys_choose.pass.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
// See https://llvm.org/LICENSE.txt for license information. | ||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
// UNSUPPORTED: c++03, c++11, c++14, c++17 | ||
// UNSUPPORTED: no-filesystem, no-localization, no-tzdb | ||
|
||
// XFAIL: libcpp-has-no-experimental-tzdb | ||
// XFAIL: availability-tzdb-missing | ||
|
||
// <chrono> | ||
|
||
// class time_zone; | ||
|
||
// template <class _Duration> | ||
// sys_time<common_type_t<Duration, seconds>> | ||
// to_sys(const local_time<Duration>& tp, choose z) const; | ||
|
||
#include <chrono> | ||
#include <format> | ||
#include <cassert> | ||
#include <string_view> | ||
|
||
#include "test_macros.h" | ||
|
||
// Tests unique conversions. To make sure the test is does not depend on changes | ||
// in the database it uses a time zone with a fixed offset. | ||
static void test_unique() { | ||
using namespace std::literals::chrono_literals; | ||
|
||
const std::chrono::time_zone* tz = std::chrono::locate_zone("Etc/GMT+1"); | ||
|
||
assert(tz->to_sys(std::chrono::local_time<std::chrono::nanoseconds>{-1ns}, std::chrono::choose::earliest) == | ||
std::chrono::sys_time<std::chrono::nanoseconds>{-1ns + 1h}); | ||
|
||
assert(tz->to_sys(std::chrono::local_time<std::chrono::microseconds>{0us}, std::chrono::choose::latest) == | ||
std::chrono::sys_time<std::chrono::microseconds>{1h}); | ||
|
||
assert(tz->to_sys( | ||
std::chrono::local_time<std::chrono::seconds>{ | ||
(std::chrono::sys_days{std::chrono::January / 1 / -21970}).time_since_epoch()}, | ||
std::chrono::choose::earliest) == | ||
std::chrono::sys_time<std::chrono::seconds>{ | ||
(std::chrono::sys_days{std::chrono::January / 1 / -21970}).time_since_epoch() + 1h}); | ||
|
||
// sys_time<common_type_t<Duration, seconds>> is seconds for the larger types | ||
assert(tz->to_sys( | ||
std::chrono::local_time<std::chrono::days>{ | ||
(std::chrono::sys_days{std::chrono::January / 1 / 21970}).time_since_epoch()}, | ||
std::chrono::choose::latest) == | ||
std::chrono::sys_time<std::chrono::seconds>{ | ||
(std::chrono::sys_days{std::chrono::January / 1 / 21970}).time_since_epoch() + 1h}); | ||
|
||
assert(tz->to_sys(std::chrono::local_time<std::chrono::weeks>{}, std::chrono::choose::earliest) == | ||
std::chrono::sys_time<std::chrono::seconds>{ | ||
(std::chrono::sys_days{std::chrono::January / 1 / 1970}).time_since_epoch() + 1h}); | ||
|
||
// Note months and years cannot be streamed; however these functions don't | ||
// throw an exception and thus can be used. | ||
assert(tz->to_sys(std::chrono::local_time<std::chrono::months>{}, std::chrono::choose::latest) == | ||
std::chrono::sys_time<std::chrono::seconds>{ | ||
(std::chrono::sys_days{std::chrono::January / 1 / 1970}).time_since_epoch() + 1h}); | ||
|
||
assert(tz->to_sys(std::chrono::local_time<std::chrono::years>{}, std::chrono::choose::earliest) == | ||
std::chrono::sys_time<std::chrono::seconds>{ | ||
(std::chrono::sys_days{std::chrono::January / 1 / 1970}).time_since_epoch() + 1h}); | ||
} | ||
|
||
// Tests non-existant conversions. | ||
static void test_nonexistent() { | ||
using namespace std::literals::chrono_literals; | ||
|
||
const std::chrono::time_zone* tz = std::chrono::locate_zone("Europe/Berlin"); | ||
|
||
// Z Europe/Berlin 0:53:28 - LMT 1893 Ap | ||
// ... | ||
// 1 DE CE%sT 1980 | ||
// 1 E CE%sT | ||
// | ||
// ... | ||
// R E 1981 ma - Mar lastSu 1u 1 S | ||
// R E 1996 ma - O lastSu 1u 0 - | ||
|
||
// 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_seconds expected{time.time_since_epoch() - 1h}; | ||
|
||
// Validates whether the database did not change. | ||
std::chrono::local_info info = tz->get_info(time); | ||
assert(info.result == std::chrono::local_info::nonexistent); | ||
|
||
assert(tz->to_sys(time + 0ns, std::chrono::choose::earliest) == expected); | ||
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); | ||
} | ||
|
||
// Tests ambiguous conversions. | ||
static void test_ambiguous() { | ||
using namespace std::literals::chrono_literals; | ||
|
||
const std::chrono::time_zone* tz = std::chrono::locate_zone("Europe/Berlin"); | ||
|
||
// Z Europe/Berlin 0:53:28 - LMT 1893 Ap | ||
// ... | ||
// 1 DE CE%sT 1980 | ||
// 1 E CE%sT | ||
// | ||
// ... | ||
// R E 1981 ma - Mar lastSu 1u 1 S | ||
// R E 1996 ma - O lastSu 1u 0 - | ||
|
||
// 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_seconds earlier{time.time_since_epoch() - 2h}; | ||
std::chrono::sys_seconds later{time.time_since_epoch() - 1h}; | ||
|
||
// Validates whether the database did not change. | ||
std::chrono::local_info info = tz->get_info(time); | ||
assert(info.result == std::chrono::local_info::ambiguous); | ||
|
||
assert(tz->to_sys(time + 0ns, std::chrono::choose::earliest) == earlier); | ||
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); | ||
} | ||
|
||
// This test does the basic validations of this function. The library function | ||
// uses `local_info get_info(const local_time<Duration>& tp)` as implementation | ||
// detail. The get_info function does extensive testing of the data. | ||
int main(int, char**) { | ||
test_unique(); | ||
test_nonexistent(); | ||
test_ambiguous(); | ||
|
||
return 0; | ||
} |