1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9// UNSUPPORTED: c++03, c++11, c++14, c++17
10// UNSUPPORTED: no-filesystem, no-localization, no-tzdb
11
12// XFAIL: libcpp-has-no-experimental-tzdb
13// XFAIL: availability-tzdb-missing
14
15// <chrono>
16
17// class time_zone;
18
19// template <class _Duration>
20// sys_time<common_type_t<Duration, seconds>>
21// to_sys(const local_time<Duration>& tp, choose z) const;
22
23#include <chrono>
24#include <format>
25#include <cassert>
26#include <string_view>
27
28#include "test_macros.h"
29
30// Tests unique conversions. To make sure the test is does not depend on changes
31// in the database it uses a time zone with a fixed offset.
32static void test_unique() {
33 using namespace std::literals::chrono_literals;
34
35 const std::chrono::time_zone* tz = std::chrono::locate_zone("Etc/GMT+1");
36
37 assert(tz->to_sys(std::chrono::local_time<std::chrono::nanoseconds>{-1ns}, std::chrono::choose::earliest) ==
38 std::chrono::sys_time<std::chrono::nanoseconds>{-1ns + 1h});
39
40 assert(tz->to_sys(std::chrono::local_time<std::chrono::microseconds>{0us}, std::chrono::choose::latest) ==
41 std::chrono::sys_time<std::chrono::microseconds>{1h});
42
43 assert(tz->to_sys(
44 std::chrono::local_time<std::chrono::seconds>{
45 (std::chrono::sys_days{std::chrono::January / 1 / -21970}).time_since_epoch()},
46 std::chrono::choose::earliest) ==
47 std::chrono::sys_time<std::chrono::seconds>{
48 (std::chrono::sys_days{std::chrono::January / 1 / -21970}).time_since_epoch() + 1h});
49
50 // sys_time<common_type_t<Duration, seconds>> is seconds for the larger types
51 assert(tz->to_sys(
52 std::chrono::local_time<std::chrono::days>{
53 (std::chrono::sys_days{std::chrono::January / 1 / 21970}).time_since_epoch()},
54 std::chrono::choose::latest) ==
55 std::chrono::sys_time<std::chrono::seconds>{
56 (std::chrono::sys_days{std::chrono::January / 1 / 21970}).time_since_epoch() + 1h});
57
58 assert(tz->to_sys(std::chrono::local_time<std::chrono::weeks>{}, std::chrono::choose::earliest) ==
59 std::chrono::sys_time<std::chrono::seconds>{
60 (std::chrono::sys_days{std::chrono::January / 1 / 1970}).time_since_epoch() + 1h});
61
62 // Note months and years cannot be streamed; however these functions don't
63 // throw an exception and thus can be used.
64 assert(tz->to_sys(std::chrono::local_time<std::chrono::months>{}, std::chrono::choose::latest) ==
65 std::chrono::sys_time<std::chrono::seconds>{
66 (std::chrono::sys_days{std::chrono::January / 1 / 1970}).time_since_epoch() + 1h});
67
68 assert(tz->to_sys(std::chrono::local_time<std::chrono::years>{}, std::chrono::choose::earliest) ==
69 std::chrono::sys_time<std::chrono::seconds>{
70 (std::chrono::sys_days{std::chrono::January / 1 / 1970}).time_since_epoch() + 1h});
71}
72
73// Tests non-existant conversions.
74static void test_nonexistent() {
75 using namespace std::literals::chrono_literals;
76
77 const std::chrono::time_zone* tz = std::chrono::locate_zone("Europe/Berlin");
78
79 // Z Europe/Berlin 0:53:28 - LMT 1893 Ap
80 // ...
81 // 1 DE CE%sT 1980
82 // 1 E CE%sT
83 //
84 // ...
85 // R E 1981 ma - Mar lastSu 1u 1 S
86 // R E 1996 ma - O lastSu 1u 0 -
87
88 // Pick an historic date where it's well known what the time zone rules were.
89 // This makes it unlikely updates to the database change these rules.
90 std::chrono::local_time<std::chrono::seconds> time{
91 (std::chrono::sys_days{std::chrono::March / 30 / 1986} + 2h).time_since_epoch()};
92
93 std::chrono::sys_seconds expected{time.time_since_epoch() - 1h};
94
95 // Validates whether the database did not change.
96 std::chrono::local_info info = tz->get_info(time);
97 assert(info.result == std::chrono::local_info::nonexistent);
98
99 assert(tz->to_sys(time + 0ns, std::chrono::choose::earliest) == expected);
100 assert(tz->to_sys(time + 0us, std::chrono::choose::latest) == expected);
101 assert(tz->to_sys(time + 0ms, std::chrono::choose::earliest) == expected);
102 assert(tz->to_sys(time + 0s, std::chrono::choose::latest) == expected);
103
104 // The entire nonexisting hour should map to the same time.
105 // For nonexistant the value of std::chrono::choose has no effect.
106 assert(tz->to_sys(time + 1s, std::chrono::choose::earliest) == expected);
107 assert(tz->to_sys(time + 1min, std::chrono::choose::latest) == expected);
108 assert(tz->to_sys(time + 30min, std::chrono::choose::earliest) == expected);
109 assert(tz->to_sys(time + 59min + 59s, std::chrono::choose::latest) == expected);
110}
111
112// Tests ambiguous conversions.
113static void test_ambiguous() {
114 using namespace std::literals::chrono_literals;
115
116 const std::chrono::time_zone* tz = std::chrono::locate_zone("Europe/Berlin");
117
118 // Z Europe/Berlin 0:53:28 - LMT 1893 Ap
119 // ...
120 // 1 DE CE%sT 1980
121 // 1 E CE%sT
122 //
123 // ...
124 // R E 1981 ma - Mar lastSu 1u 1 S
125 // R E 1996 ma - O lastSu 1u 0 -
126
127 // Pick an historic date where it's well known what the time zone rules were.
128 // This makes it unlikely updates to the database change these rules.
129 std::chrono::local_time<std::chrono::seconds> time{
130 (std::chrono::sys_days{std::chrono::September / 28 / 1986} + 2h).time_since_epoch()};
131
132 std::chrono::sys_seconds earlier{time.time_since_epoch() - 2h};
133 std::chrono::sys_seconds later{time.time_since_epoch() - 1h};
134
135 // Validates whether the database did not change.
136 std::chrono::local_info info = tz->get_info(time);
137 assert(info.result == std::chrono::local_info::ambiguous);
138
139 assert(tz->to_sys(time + 0ns, std::chrono::choose::earliest) == earlier);
140 assert(tz->to_sys(time + 0us, std::chrono::choose::latest) == later);
141 assert(tz->to_sys(time + 0ms, std::chrono::choose::earliest) == earlier);
142 assert(tz->to_sys(time + 0s, std::chrono::choose::latest) == later);
143
144 // Test times in the ambigious hour
145 assert(tz->to_sys(time + 1s, std::chrono::choose::earliest) == earlier + 1s);
146 assert(tz->to_sys(time + 1min, std::chrono::choose::latest) == later + 1min);
147 assert(tz->to_sys(time + 30min, std::chrono::choose::earliest) == earlier + 30min);
148 assert(tz->to_sys(time + 59min + 59s, std::chrono::choose::latest) == later + 59min + 59s);
149}
150
151// This test does the basic validations of this function. The library function
152// uses `local_info get_info(const local_time<Duration>& tp)` as implementation
153// detail. The get_info function does extensive testing of the data.
154int main(int, char**) {
155 test_unique();
156 test_nonexistent();
157 test_ambiguous();
158
159 return 0;
160}
161

source code of libcxx/test/std/time/time.zone/time.zone.timezone/time.zone.members/to_sys_choose.pass.cpp