1 | // -*- C++ -*- |
2 | //===----------------------------------------------------------------------===// |
3 | // |
4 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
5 | // See https://llvm.org/LICENSE.txt for license information. |
6 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
7 | // |
8 | //===----------------------------------------------------------------------===// |
9 | |
10 | // For information see https://libcxx.llvm.org/DesignDocs/TimeZone.html |
11 | |
12 | #ifndef _LIBCPP___CHRONO_ZONED_TIME_H |
13 | #define _LIBCPP___CHRONO_ZONED_TIME_H |
14 | |
15 | #include <version> |
16 | // Enable the contents of the header only when libc++ was built with experimental features enabled. |
17 | #if !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB) |
18 | |
19 | # include <__chrono/calendar.h> |
20 | # include <__chrono/duration.h> |
21 | # include <__chrono/sys_info.h> |
22 | # include <__chrono/system_clock.h> |
23 | # include <__chrono/time_zone.h> |
24 | # include <__chrono/tzdb_list.h> |
25 | # include <__config> |
26 | # include <__fwd/string_view.h> |
27 | # include <__type_traits/common_type.h> |
28 | # include <__type_traits/conditional.h> |
29 | # include <__type_traits/remove_cvref.h> |
30 | # include <__utility/move.h> |
31 | |
32 | # if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) |
33 | # pragma GCC system_header |
34 | # endif |
35 | |
36 | _LIBCPP_PUSH_MACROS |
37 | # include <__undef_macros> |
38 | |
39 | _LIBCPP_BEGIN_NAMESPACE_STD |
40 | |
41 | # if _LIBCPP_STD_VER >= 20 && !defined(_LIBCPP_HAS_NO_TIME_ZONE_DATABASE) && !defined(_LIBCPP_HAS_NO_FILESYSTEM) && \ |
42 | !defined(_LIBCPP_HAS_NO_LOCALIZATION) |
43 | |
44 | namespace chrono { |
45 | |
46 | template <class> |
47 | struct zoned_traits {}; |
48 | |
49 | template <> |
50 | struct zoned_traits<const time_zone*> { |
51 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static const time_zone* default_zone() { return chrono::locate_zone(name: "UTC" ); } |
52 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static const time_zone* locate_zone(string_view __name) { |
53 | return chrono::locate_zone(__name); |
54 | } |
55 | }; |
56 | |
57 | template <class _Duration, class _TimeZonePtr = const time_zone*> |
58 | class zoned_time { |
59 | // [time.zone.zonedtime.ctor]/2 |
60 | static_assert(__is_duration<_Duration>::value, |
61 | "the program is ill-formed since _Duration is not a specialization of std::chrono::duration" ); |
62 | |
63 | // The wording uses the constraints like |
64 | // constructible_from<zoned_time, decltype(__traits::locate_zone(string_view{}))> |
65 | // Using these constraints in the code causes the compiler to give an |
66 | // error that the constraint depends on itself. To avoid that issue use |
67 | // the fact it is possible to create this object from a _TimeZonePtr. |
68 | using __traits = zoned_traits<_TimeZonePtr>; |
69 | |
70 | public: |
71 | using duration = common_type_t<_Duration, seconds>; |
72 | |
73 | _LIBCPP_HIDE_FROM_ABI zoned_time() |
74 | requires requires { __traits::default_zone(); } |
75 | : __zone_{__traits::default_zone()}, __tp_{} {} |
76 | |
77 | _LIBCPP_HIDE_FROM_ABI zoned_time(const zoned_time&) = default; |
78 | _LIBCPP_HIDE_FROM_ABI zoned_time& operator=(const zoned_time&) = default; |
79 | |
80 | _LIBCPP_HIDE_FROM_ABI zoned_time(const sys_time<_Duration>& __tp) |
81 | requires requires { __traits::default_zone(); } |
82 | : __zone_{__traits::default_zone()}, __tp_{__tp} {} |
83 | |
84 | _LIBCPP_HIDE_FROM_ABI explicit zoned_time(_TimeZonePtr __zone) : __zone_{std::move(__zone)}, __tp_{} {} |
85 | |
86 | _LIBCPP_HIDE_FROM_ABI explicit zoned_time(string_view __name) |
87 | requires(requires { __traits::locate_zone(string_view{}); } && |
88 | constructible_from<_TimeZonePtr, decltype(__traits::locate_zone(string_view{}))>) |
89 | : __zone_{__traits::locate_zone(__name)}, __tp_{} {} |
90 | |
91 | template <class _Duration2> |
92 | _LIBCPP_HIDE_FROM_ABI zoned_time(const zoned_time<_Duration2, _TimeZonePtr>& __zt) |
93 | requires is_convertible_v<sys_time<_Duration2>, sys_time<_Duration>> |
94 | : __zone_{__zt.get_time_zone()}, __tp_{__zt.get_sys_time()} {} |
95 | |
96 | _LIBCPP_HIDE_FROM_ABI zoned_time(_TimeZonePtr __zone, const sys_time<_Duration>& __tp) |
97 | : __zone_{std::move(__zone)}, __tp_{__tp} {} |
98 | |
99 | _LIBCPP_HIDE_FROM_ABI zoned_time(string_view __name, const sys_time<_Duration>& __tp) |
100 | requires requires { _TimeZonePtr{__traits::locate_zone(string_view{})}; } |
101 | : zoned_time{__traits::locate_zone(__name), __tp} {} |
102 | |
103 | _LIBCPP_HIDE_FROM_ABI zoned_time(_TimeZonePtr __zone, const local_time<_Duration>& __tp) |
104 | requires(is_convertible_v<decltype(std::declval<_TimeZonePtr&>() -> to_sys(local_time<_Duration>{})), |
105 | sys_time<duration>>) |
106 | : __zone_{std::move(__zone)}, __tp_{__zone_->to_sys(__tp)} {} |
107 | |
108 | _LIBCPP_HIDE_FROM_ABI zoned_time(string_view __name, const local_time<_Duration>& __tp) |
109 | requires(requires { |
110 | _TimeZonePtr{__traits::locate_zone(string_view{})}; |
111 | } && is_convertible_v<decltype(std::declval<_TimeZonePtr&>() -> to_sys(local_time<_Duration>{})), |
112 | sys_time<duration>>) |
113 | : zoned_time{__traits::locate_zone(__name), __tp} {} |
114 | |
115 | _LIBCPP_HIDE_FROM_ABI zoned_time(_TimeZonePtr __zone, const local_time<_Duration>& __tp, choose __c) |
116 | requires(is_convertible_v< |
117 | decltype(std::declval<_TimeZonePtr&>() -> to_sys(local_time<_Duration>{}, choose::earliest)), |
118 | sys_time<duration>>) |
119 | : __zone_{std::move(__zone)}, __tp_{__zone_->to_sys(__tp, __c)} {} |
120 | |
121 | _LIBCPP_HIDE_FROM_ABI zoned_time(string_view __name, const local_time<_Duration>& __tp, choose __c) |
122 | requires(requires { |
123 | _TimeZonePtr{__traits::locate_zone(string_view{})}; |
124 | } && is_convertible_v<decltype(std::declval<_TimeZonePtr&>() -> to_sys(local_time<_Duration>{}, choose::earliest)), |
125 | sys_time<duration>>) |
126 | : zoned_time{__traits::locate_zone(__name), __tp, __c} {} |
127 | |
128 | template <class _Duration2, class _TimeZonePtr2> |
129 | _LIBCPP_HIDE_FROM_ABI zoned_time(_TimeZonePtr __zone, const zoned_time<_Duration2, _TimeZonePtr2>& __zt) |
130 | requires is_convertible_v<sys_time<_Duration2>, sys_time<_Duration>> |
131 | : __zone_{std::move(__zone)}, __tp_{__zt.get_sys_time()} {} |
132 | |
133 | // per wording choose has no effect |
134 | template <class _Duration2, class _TimeZonePtr2> |
135 | _LIBCPP_HIDE_FROM_ABI zoned_time(_TimeZonePtr __zone, const zoned_time<_Duration2, _TimeZonePtr2>& __zt, choose) |
136 | requires is_convertible_v<sys_time<_Duration2>, sys_time<_Duration>> |
137 | : __zone_{std::move(__zone)}, __tp_{__zt.get_sys_time()} {} |
138 | |
139 | template <class _Duration2, class _TimeZonePtr2> |
140 | _LIBCPP_HIDE_FROM_ABI zoned_time(string_view __name, const zoned_time<_Duration2, _TimeZonePtr2>& __zt) |
141 | requires(requires { |
142 | _TimeZonePtr{__traits::locate_zone(string_view{})}; |
143 | } && is_convertible_v<sys_time<_Duration2>, sys_time<_Duration>>) |
144 | : zoned_time{__traits::locate_zone(__name), __zt} {} |
145 | |
146 | template <class _Duration2, class _TimeZonePtr2> |
147 | _LIBCPP_HIDE_FROM_ABI zoned_time(string_view __name, const zoned_time<_Duration2, _TimeZonePtr2>& __zt, choose __c) |
148 | requires(requires { |
149 | _TimeZonePtr{__traits::locate_zone(string_view{})}; |
150 | } && is_convertible_v<sys_time<_Duration2>, sys_time<_Duration>>) |
151 | : zoned_time{__traits::locate_zone(__name), __zt, __c} {} |
152 | |
153 | _LIBCPP_HIDE_FROM_ABI zoned_time& operator=(const sys_time<_Duration>& __tp) { |
154 | __tp_ = __tp; |
155 | return *this; |
156 | } |
157 | |
158 | _LIBCPP_HIDE_FROM_ABI zoned_time& operator=(const local_time<_Duration>& __tp) { |
159 | // TODO TZDB This seems wrong. |
160 | // Assigning a non-existent or ambiguous time will throw and not satisfy |
161 | // the post condition. This seems quite odd; I constructed an object with |
162 | // choose::earliest and that choice is not respected. |
163 | // what did LEWG do with this. |
164 | // MSVC STL and libstdc++ behave the same |
165 | __tp_ = __zone_->to_sys(__tp); |
166 | return *this; |
167 | } |
168 | |
169 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI operator sys_time<duration>() const { return get_sys_time(); } |
170 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI explicit operator local_time<duration>() const { return get_local_time(); } |
171 | |
172 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _TimeZonePtr get_time_zone() const { return __zone_; } |
173 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI local_time<duration> get_local_time() const { return __zone_->to_local(__tp_); } |
174 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI sys_time<duration> get_sys_time() const { return __tp_; } |
175 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI sys_info get_info() const { return __zone_->get_info(__tp_); } |
176 | |
177 | private: |
178 | _TimeZonePtr __zone_; |
179 | sys_time<duration> __tp_; |
180 | }; |
181 | |
182 | zoned_time() -> zoned_time<seconds>; |
183 | |
184 | template <class _Duration> |
185 | zoned_time(sys_time<_Duration>) -> zoned_time<common_type_t<_Duration, seconds>>; |
186 | |
187 | template <class _TimeZonePtrOrName> |
188 | using __time_zone_representation = |
189 | conditional_t<is_convertible_v<_TimeZonePtrOrName, string_view>, |
190 | const time_zone*, |
191 | remove_cvref_t<_TimeZonePtrOrName>>; |
192 | |
193 | template <class _TimeZonePtrOrName> |
194 | zoned_time(_TimeZonePtrOrName&&) -> zoned_time<seconds, __time_zone_representation<_TimeZonePtrOrName>>; |
195 | |
196 | template <class _TimeZonePtrOrName, class _Duration> |
197 | zoned_time(_TimeZonePtrOrName&&, sys_time<_Duration>) |
198 | -> zoned_time<common_type_t<_Duration, seconds>, __time_zone_representation<_TimeZonePtrOrName>>; |
199 | |
200 | template <class _TimeZonePtrOrName, class _Duration> |
201 | zoned_time(_TimeZonePtrOrName&&, local_time<_Duration>, choose = choose::earliest) |
202 | -> zoned_time<common_type_t<_Duration, seconds>, __time_zone_representation<_TimeZonePtrOrName>>; |
203 | |
204 | template <class _Duration, class _TimeZonePtrOrName, class TimeZonePtr2> |
205 | zoned_time(_TimeZonePtrOrName&&, zoned_time<_Duration, TimeZonePtr2>, choose = choose::earliest) |
206 | -> zoned_time<common_type_t<_Duration, seconds>, __time_zone_representation<_TimeZonePtrOrName>>; |
207 | |
208 | using zoned_seconds = zoned_time<seconds>; |
209 | |
210 | template <class _Duration1, class _Duration2, class _TimeZonePtr> |
211 | _LIBCPP_HIDE_FROM_ABI bool |
212 | operator==(const zoned_time<_Duration1, _TimeZonePtr>& __lhs, const zoned_time<_Duration2, _TimeZonePtr>& __rhs) { |
213 | return __lhs.get_time_zone() == __rhs.get_time_zone() && __lhs.get_sys_time() == __rhs.get_sys_time(); |
214 | } |
215 | |
216 | } // namespace chrono |
217 | |
218 | # endif // _LIBCPP_STD_VER >= 20 && !defined(_LIBCPP_HAS_NO_TIME_ZONE_DATABASE) && !defined(_LIBCPP_HAS_NO_FILESYSTEM) |
219 | // && !defined(_LIBCPP_HAS_NO_LOCALIZATION) |
220 | |
221 | _LIBCPP_END_NAMESPACE_STD |
222 | |
223 | _LIBCPP_POP_MACROS |
224 | |
225 | #endif // !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB) |
226 | |
227 | #endif // _LIBCPP___CHRONO_ZONED_TIME_H |
228 | |