xref: /llvm-project/libcxx/test/std/time/time.zone/time.zone.timezone/time.zone.members/to_sys.pass.cpp (revision b27360c346a529affde40150f46b967b616a2144)
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