177116bd7SMark de Wever //===----------------------------------------------------------------------===// 277116bd7SMark de Wever // 377116bd7SMark de Wever // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 477116bd7SMark de Wever // See https://llvm.org/LICENSE.txt for license information. 577116bd7SMark de Wever // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 677116bd7SMark de Wever // 777116bd7SMark de Wever //===----------------------------------------------------------------------===// 877116bd7SMark de Wever 977116bd7SMark de Wever // UNSUPPORTED: c++03, c++11, c++14, c++17 1077116bd7SMark de Wever // UNSUPPORTED: no-filesystem, no-localization, no-tzdb 1177116bd7SMark de Wever 1277116bd7SMark de Wever // XFAIL: libcpp-has-no-experimental-tzdb 1377116bd7SMark de Wever // XFAIL: availability-tzdb-missing 1477116bd7SMark de Wever 1577116bd7SMark de Wever // <chrono> 1677116bd7SMark de Wever 1777116bd7SMark de Wever // class time_zone; 1877116bd7SMark de Wever 1977116bd7SMark de Wever // template <class _Duration> 2077116bd7SMark de Wever // sys_time<common_type_t<Duration, seconds>> 2177116bd7SMark de Wever // to_sys(const local_time<Duration>& tp) const; 2277116bd7SMark de Wever 2377116bd7SMark de Wever #include <chrono> 2477116bd7SMark de Wever #include <format> 2577116bd7SMark de Wever #include <cassert> 2677116bd7SMark de Wever #include <string_view> 2777116bd7SMark de Wever 2877116bd7SMark de Wever #include "test_macros.h" 2977116bd7SMark de Wever #include "assert_macros.h" 3077116bd7SMark de Wever #include "concat_macros.h" 3177116bd7SMark de Wever 3277116bd7SMark de Wever // Tests unique conversions. To make sure the test is does not depend on changes 3377116bd7SMark de Wever // in the database it uses a time zone with a fixed offset. 3477116bd7SMark de Wever static void test_unique() { 3577116bd7SMark de Wever using namespace std::literals::chrono_literals; 3677116bd7SMark de Wever 3777116bd7SMark de Wever const std::chrono::time_zone* tz = std::chrono::locate_zone("Etc/GMT+1"); 3877116bd7SMark de Wever 3977116bd7SMark de Wever assert(tz->to_sys(std::chrono::local_time<std::chrono::nanoseconds>{-1ns}) == 4077116bd7SMark de Wever std::chrono::sys_time<std::chrono::nanoseconds>{-1ns + 1h}); 4177116bd7SMark de Wever 4277116bd7SMark de Wever assert(tz->to_sys(std::chrono::local_time<std::chrono::microseconds>{0us}) == 4377116bd7SMark de Wever std::chrono::sys_time<std::chrono::microseconds>{1h}); 4477116bd7SMark de Wever 4577116bd7SMark de Wever assert(tz->to_sys(std::chrono::local_time<std::chrono::seconds>{ 4677116bd7SMark de Wever (std::chrono::sys_days{std::chrono::January / 1 / -21970}).time_since_epoch()}) == 4777116bd7SMark de Wever std::chrono::sys_time<std::chrono::seconds>{ 4877116bd7SMark de Wever (std::chrono::sys_days{std::chrono::January / 1 / -21970}).time_since_epoch() + 1h}); 4977116bd7SMark de Wever 5077116bd7SMark de Wever // sys_time<common_type_t<Duration, seconds>> is seconds for the larger types 5177116bd7SMark de Wever assert(tz->to_sys(std::chrono::local_time<std::chrono::days>{ 5277116bd7SMark de Wever (std::chrono::sys_days{std::chrono::January / 1 / 21970}).time_since_epoch()}) == 5377116bd7SMark de Wever std::chrono::sys_time<std::chrono::seconds>{ 5477116bd7SMark de Wever (std::chrono::sys_days{std::chrono::January / 1 / 21970}).time_since_epoch() + 1h}); 5577116bd7SMark de Wever 5677116bd7SMark de Wever assert(tz->to_sys(std::chrono::local_time<std::chrono::weeks>{}) == 5777116bd7SMark de Wever std::chrono::sys_time<std::chrono::seconds>{ 5877116bd7SMark de Wever (std::chrono::sys_days{std::chrono::January / 1 / 1970}).time_since_epoch() + 1h}); 5977116bd7SMark de Wever 6077116bd7SMark de Wever // Note months and years can not be streamed; thus the function cannot be 6177116bd7SMark de Wever // instantiated for these types. (Even when there is no exception thrown.) 6277116bd7SMark de Wever } 6377116bd7SMark de Wever 6477116bd7SMark de Wever // Tests non-existant conversions. 6577116bd7SMark de Wever static void test_nonexistent() { 6677116bd7SMark de Wever #ifndef TEST_HAS_NO_EXCEPTIONS 6777116bd7SMark de Wever using namespace std::literals::chrono_literals; 6877116bd7SMark de Wever 6977116bd7SMark de Wever const std::chrono::time_zone* tz = std::chrono::locate_zone("Europe/Berlin"); 7077116bd7SMark de Wever 7177116bd7SMark de Wever // Z Europe/Berlin 0:53:28 - LMT 1893 Ap 7277116bd7SMark de Wever // ... 7377116bd7SMark de Wever // 1 DE CE%sT 1980 7477116bd7SMark de Wever // 1 E CE%sT 7577116bd7SMark de Wever // 7677116bd7SMark de Wever // ... 7777116bd7SMark de Wever // R E 1981 ma - Mar lastSu 1u 1 S 7877116bd7SMark de Wever // R E 1996 ma - O lastSu 1u 0 - 7977116bd7SMark de Wever 8077116bd7SMark de Wever // Pick an historic date where it's well known what the time zone rules were. 8177116bd7SMark de Wever // This makes it unlikely updates to the database change these rules. 8277116bd7SMark de Wever std::chrono::local_time<std::chrono::seconds> time{ 8377116bd7SMark de Wever (std::chrono::sys_days{std::chrono::March / 30 / 1986} + 2h + 30min).time_since_epoch()}; 8477116bd7SMark de Wever 8577116bd7SMark de Wever // Validates whether the database did not change. 8677116bd7SMark de Wever std::chrono::local_info info = tz->get_info(time); 8777116bd7SMark de Wever assert(info.result == std::chrono::local_info::nonexistent); 8877116bd7SMark de Wever 8977116bd7SMark de Wever TEST_VALIDATE_EXCEPTION( 9077116bd7SMark de Wever std::chrono::nonexistent_local_time, 9177116bd7SMark de Wever [&]([[maybe_unused]] const std::chrono::nonexistent_local_time& e) { 92*b27360c3SStephan T. Lavavej [[maybe_unused]] std::string_view what = 9377116bd7SMark de Wever R"(1986-03-30 02:30:00.000000000 is in a gap between 9477116bd7SMark de Wever 1986-03-30 02:00:00 CET and 9577116bd7SMark de Wever 1986-03-30 03:00:00 CEST which are both equivalent to 9677116bd7SMark de Wever 1986-03-30 01:00:00 UTC)"; 9777116bd7SMark de Wever TEST_LIBCPP_REQUIRE( 9877116bd7SMark de Wever e.what() == what, 9977116bd7SMark de Wever TEST_WRITE_CONCATENATED("Expected exception\n", what, "\n\nActual exception\n", e.what(), '\n')); 10077116bd7SMark de Wever }, 10177116bd7SMark de Wever tz->to_sys(time + 0ns)); 10277116bd7SMark de Wever 10377116bd7SMark de Wever TEST_VALIDATE_EXCEPTION( 10477116bd7SMark de Wever std::chrono::nonexistent_local_time, 10577116bd7SMark de Wever [&]([[maybe_unused]] const std::chrono::nonexistent_local_time& e) { 106*b27360c3SStephan T. Lavavej [[maybe_unused]] std::string_view what = 10777116bd7SMark de Wever R"(1986-03-30 02:30:00.000000 is in a gap between 10877116bd7SMark de Wever 1986-03-30 02:00:00 CET and 10977116bd7SMark de Wever 1986-03-30 03:00:00 CEST which are both equivalent to 11077116bd7SMark de Wever 1986-03-30 01:00:00 UTC)"; 11177116bd7SMark de Wever TEST_LIBCPP_REQUIRE( 11277116bd7SMark de Wever e.what() == what, 11377116bd7SMark de Wever TEST_WRITE_CONCATENATED("Expected exception\n", what, "\n\nActual exception\n", e.what(), '\n')); 11477116bd7SMark de Wever }, 11577116bd7SMark de Wever tz->to_sys(time + 0us)); 11677116bd7SMark de Wever 11777116bd7SMark de Wever TEST_VALIDATE_EXCEPTION( 11877116bd7SMark de Wever std::chrono::nonexistent_local_time, 11977116bd7SMark de Wever [&]([[maybe_unused]] const std::chrono::nonexistent_local_time& e) { 120*b27360c3SStephan T. Lavavej [[maybe_unused]] std::string_view what = 12177116bd7SMark de Wever R"(1986-03-30 02:30:00.000 is in a gap between 12277116bd7SMark de Wever 1986-03-30 02:00:00 CET and 12377116bd7SMark de Wever 1986-03-30 03:00:00 CEST which are both equivalent to 12477116bd7SMark de Wever 1986-03-30 01:00:00 UTC)"; 12577116bd7SMark de Wever TEST_LIBCPP_REQUIRE( 12677116bd7SMark de Wever e.what() == what, 12777116bd7SMark de Wever TEST_WRITE_CONCATENATED("Expected exception\n", what, "\n\nActual exception\n", e.what(), '\n')); 12877116bd7SMark de Wever }, 12977116bd7SMark de Wever tz->to_sys(time + 0ms)); 13077116bd7SMark de Wever 13177116bd7SMark de Wever TEST_VALIDATE_EXCEPTION( 13277116bd7SMark de Wever std::chrono::nonexistent_local_time, 13377116bd7SMark de Wever [&]([[maybe_unused]] const std::chrono::nonexistent_local_time& e) { 134*b27360c3SStephan T. Lavavej [[maybe_unused]] std::string_view what = 13577116bd7SMark de Wever R"(1986-03-30 02:30:00 is in a gap between 13677116bd7SMark de Wever 1986-03-30 02:00:00 CET and 13777116bd7SMark de Wever 1986-03-30 03:00:00 CEST which are both equivalent to 13877116bd7SMark de Wever 1986-03-30 01:00:00 UTC)"; 13977116bd7SMark de Wever TEST_LIBCPP_REQUIRE( 14077116bd7SMark de Wever e.what() == what, 14177116bd7SMark de Wever TEST_WRITE_CONCATENATED("Expected exception\n", what, "\n\nActual exception\n", e.what(), '\n')); 14277116bd7SMark de Wever }, 14377116bd7SMark de Wever tz->to_sys(time + 0s)); 14477116bd7SMark de Wever 14577116bd7SMark de Wever #endif // TEST_HAS_NO_EXCEPTIONS 14677116bd7SMark de Wever } 14777116bd7SMark de Wever 14877116bd7SMark de Wever // Tests ambiguous conversions. 14977116bd7SMark de Wever static void test_ambiguous() { 15077116bd7SMark de Wever #ifndef TEST_HAS_NO_EXCEPTIONS 15177116bd7SMark de Wever using namespace std::literals::chrono_literals; 15277116bd7SMark de Wever 15377116bd7SMark de Wever const std::chrono::time_zone* tz = std::chrono::locate_zone("Europe/Berlin"); 15477116bd7SMark de Wever 15577116bd7SMark de Wever // Z Europe/Berlin 0:53:28 - LMT 1893 Ap 15677116bd7SMark de Wever // ... 15777116bd7SMark de Wever // 1 DE CE%sT 1980 15877116bd7SMark de Wever // 1 E CE%sT 15977116bd7SMark de Wever // 16077116bd7SMark de Wever // ... 16177116bd7SMark de Wever // R E 1981 ma - Mar lastSu 1u 1 S 16277116bd7SMark de Wever // R E 1996 ma - O lastSu 1u 0 - 16377116bd7SMark de Wever 16477116bd7SMark de Wever // Pick an historic date where it's well known what the time zone rules were. 16577116bd7SMark de Wever // This makes it unlikely updates to the database change these rules. 16677116bd7SMark de Wever std::chrono::local_time<std::chrono::seconds> time{ 16777116bd7SMark de Wever (std::chrono::sys_days{std::chrono::September / 28 / 1986} + 2h + 30min).time_since_epoch()}; 16877116bd7SMark de Wever 16977116bd7SMark de Wever // Validates whether the database did not change. 17077116bd7SMark de Wever std::chrono::local_info info = tz->get_info(time); 17177116bd7SMark de Wever assert(info.result == std::chrono::local_info::ambiguous); 17277116bd7SMark de Wever 17377116bd7SMark de Wever TEST_VALIDATE_EXCEPTION( 17477116bd7SMark de Wever std::chrono::ambiguous_local_time, 17577116bd7SMark de Wever [&]([[maybe_unused]] const std::chrono::ambiguous_local_time& e) { 176*b27360c3SStephan T. Lavavej [[maybe_unused]] std::string_view what = 17777116bd7SMark de Wever R"(1986-09-28 02:30:00.000000000 is ambiguous. It could be 17877116bd7SMark de Wever 1986-09-28 02:30:00.000000000 CEST == 1986-09-28 00:30:00.000000000 UTC or 17977116bd7SMark de Wever 1986-09-28 02:30:00.000000000 CET == 1986-09-28 01:30:00.000000000 UTC)"; 18077116bd7SMark de Wever TEST_LIBCPP_REQUIRE( 18177116bd7SMark de Wever e.what() == what, 18277116bd7SMark de Wever TEST_WRITE_CONCATENATED("Expected exception\n", what, "\n\nActual exception\n", e.what(), '\n')); 18377116bd7SMark de Wever }, 18477116bd7SMark de Wever tz->to_sys(time + 0ns)); 18577116bd7SMark de Wever 18677116bd7SMark de Wever TEST_VALIDATE_EXCEPTION( 18777116bd7SMark de Wever std::chrono::ambiguous_local_time, 18877116bd7SMark de Wever [&]([[maybe_unused]] const std::chrono::ambiguous_local_time& e) { 189*b27360c3SStephan T. Lavavej [[maybe_unused]] std::string_view what = 19077116bd7SMark de Wever R"(1986-09-28 02:30:00.000000 is ambiguous. It could be 19177116bd7SMark de Wever 1986-09-28 02:30:00.000000 CEST == 1986-09-28 00:30:00.000000 UTC or 19277116bd7SMark de Wever 1986-09-28 02:30:00.000000 CET == 1986-09-28 01:30:00.000000 UTC)"; 19377116bd7SMark de Wever TEST_LIBCPP_REQUIRE( 19477116bd7SMark de Wever e.what() == what, 19577116bd7SMark de Wever TEST_WRITE_CONCATENATED("Expected exception\n", what, "\n\nActual exception\n", e.what(), '\n')); 19677116bd7SMark de Wever }, 19777116bd7SMark de Wever tz->to_sys(time + 0us)); 19877116bd7SMark de Wever 19977116bd7SMark de Wever TEST_VALIDATE_EXCEPTION( 20077116bd7SMark de Wever std::chrono::ambiguous_local_time, 20177116bd7SMark de Wever [&]([[maybe_unused]] const std::chrono::ambiguous_local_time& e) { 202*b27360c3SStephan T. Lavavej [[maybe_unused]] std::string_view what = 20377116bd7SMark de Wever R"(1986-09-28 02:30:00.000 is ambiguous. It could be 20477116bd7SMark de Wever 1986-09-28 02:30:00.000 CEST == 1986-09-28 00:30:00.000 UTC or 20577116bd7SMark de Wever 1986-09-28 02:30:00.000 CET == 1986-09-28 01:30:00.000 UTC)"; 20677116bd7SMark de Wever TEST_LIBCPP_REQUIRE( 20777116bd7SMark de Wever e.what() == what, 20877116bd7SMark de Wever TEST_WRITE_CONCATENATED("Expected exception\n", what, "\n\nActual exception\n", e.what(), '\n')); 20977116bd7SMark de Wever }, 21077116bd7SMark de Wever tz->to_sys(time + 0ms)); 21177116bd7SMark de Wever 21277116bd7SMark de Wever TEST_VALIDATE_EXCEPTION( 21377116bd7SMark de Wever std::chrono::ambiguous_local_time, 21477116bd7SMark de Wever [&]([[maybe_unused]] const std::chrono::ambiguous_local_time& e) { 215*b27360c3SStephan T. Lavavej [[maybe_unused]] std::string_view what = 21677116bd7SMark de Wever R"(1986-09-28 02:30:00 is ambiguous. It could be 21777116bd7SMark de Wever 1986-09-28 02:30:00 CEST == 1986-09-28 00:30:00 UTC or 21877116bd7SMark de Wever 1986-09-28 02:30:00 CET == 1986-09-28 01:30:00 UTC)"; 21977116bd7SMark de Wever TEST_LIBCPP_REQUIRE( 22077116bd7SMark de Wever e.what() == what, 22177116bd7SMark de Wever TEST_WRITE_CONCATENATED("Expected exception\n", what, "\n\nActual exception\n", e.what(), '\n')); 22277116bd7SMark de Wever }, 22377116bd7SMark de Wever tz->to_sys(time + 0s)); 22477116bd7SMark de Wever 22577116bd7SMark de Wever #endif // TEST_HAS_NO_EXCEPTIONS 22677116bd7SMark de Wever } 22777116bd7SMark de Wever 22877116bd7SMark de Wever // This test does the basic validations of this function. The library function 22977116bd7SMark de Wever // uses `local_info get_info(const local_time<Duration>& tp)` as implementation 23077116bd7SMark de Wever // detail. The get_info function does extensive testing of the data. 23177116bd7SMark de Wever int main(int, char**) { 23277116bd7SMark de Wever test_unique(); 23377116bd7SMark de Wever test_nonexistent(); 23477116bd7SMark de Wever test_ambiguous(); 23577116bd7SMark de Wever 23677116bd7SMark de Wever return 0; 23777116bd7SMark de Wever } 238