2 //===----------------------------------------------------------------------===//
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
8 //===----------------------------------------------------------------------===//
10 // For information see https://libcxx.llvm.org/DesignDocs/TimeZone.html
12 #ifndef _LIBCPP___CHRONO_ZONED_TIME_H
13 #define _LIBCPP___CHRONO_ZONED_TIME_H
16 // Enable the contents of the header only when libc++ was built with experimental features enabled.
17 #if !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB)
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 <__concepts/constructible.h>
27 # include <__type_traits/common_type.h>
28 # include <__type_traits/conditional.h>
29 # include <__type_traits/remove_cvref.h>
30 # include <__utility/declval.h>
31 # include <__utility/move.h>
32 # include <string_view>
34 # if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
35 # pragma GCC system_header
39 # include <__undef_macros>
41 _LIBCPP_BEGIN_NAMESPACE_STD
43 # if _LIBCPP_STD_VER >= 20 && _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM && _LIBCPP_HAS_LOCALIZATION
48 struct zoned_traits
{};
51 struct zoned_traits
<const time_zone
*> {
52 [[nodiscard
]] _LIBCPP_HIDE_FROM_ABI
static const time_zone
* default_zone() { return chrono::locate_zone("UTC"); }
53 [[nodiscard
]] _LIBCPP_HIDE_FROM_ABI
static const time_zone
* locate_zone(string_view __name
) {
54 return chrono::locate_zone(__name
);
58 template <class _Duration
, class _TimeZonePtr
= const time_zone
*>
60 // [time.zone.zonedtime.ctor]/2
61 static_assert(__is_duration_v
<_Duration
>,
62 "the program is ill-formed since _Duration is not a specialization of std::chrono::duration");
64 // The wording uses the constraints like
65 // constructible_from<zoned_time, decltype(__traits::locate_zone(string_view{}))>
66 // Using these constraints in the code causes the compiler to give an
67 // error that the constraint depends on itself. To avoid that issue use
68 // the fact it is possible to create this object from a _TimeZonePtr.
69 using __traits
= zoned_traits
<_TimeZonePtr
>;
72 using duration
= common_type_t
<_Duration
, seconds
>;
74 _LIBCPP_HIDE_FROM_ABI
zoned_time()
75 requires requires
{ __traits::default_zone(); }
76 : __zone_
{__traits::default_zone()}, __tp_
{} {}
78 _LIBCPP_HIDE_FROM_ABI
zoned_time(const zoned_time
&) = default;
79 _LIBCPP_HIDE_FROM_ABI zoned_time
& operator=(const zoned_time
&) = default;
81 _LIBCPP_HIDE_FROM_ABI
zoned_time(const sys_time
<_Duration
>& __tp
)
82 requires requires
{ __traits::default_zone(); }
83 : __zone_
{__traits::default_zone()}, __tp_
{__tp
} {}
85 _LIBCPP_HIDE_FROM_ABI
explicit zoned_time(_TimeZonePtr __zone
) : __zone_
{std::move(__zone
)}, __tp_
{} {}
87 _LIBCPP_HIDE_FROM_ABI
explicit zoned_time(string_view __name
)
88 requires(requires
{ __traits::locate_zone(string_view
{}); } &&
89 constructible_from
<_TimeZonePtr
, decltype(__traits::locate_zone(string_view
{}))>)
90 : __zone_
{__traits::locate_zone(__name
)}, __tp_
{} {}
92 template <class _Duration2
>
93 _LIBCPP_HIDE_FROM_ABI
zoned_time(const zoned_time
<_Duration2
, _TimeZonePtr
>& __zt
)
94 requires is_convertible_v
<sys_time
<_Duration2
>, sys_time
<_Duration
>>
95 : __zone_
{__zt
.get_time_zone()}, __tp_
{__zt
.get_sys_time()} {}
97 _LIBCPP_HIDE_FROM_ABI
zoned_time(_TimeZonePtr __zone
, const sys_time
<_Duration
>& __tp
)
98 : __zone_
{std::move(__zone
)}, __tp_
{__tp
} {}
100 _LIBCPP_HIDE_FROM_ABI
zoned_time(string_view __name
, const sys_time
<_Duration
>& __tp
)
101 requires requires
{ _TimeZonePtr
{__traits::locate_zone(string_view
{})}; }
102 : zoned_time
{__traits::locate_zone(__name
), __tp
} {}
104 _LIBCPP_HIDE_FROM_ABI
zoned_time(_TimeZonePtr __zone
, const local_time
<_Duration
>& __tp
)
105 requires(is_convertible_v
<decltype(std::declval
<_TimeZonePtr
&>() -> to_sys(local_time
<_Duration
>{})),
107 : __zone_
{std::move(__zone
)}, __tp_
{__zone_
->to_sys(__tp
)} {}
109 _LIBCPP_HIDE_FROM_ABI
zoned_time(string_view __name
, const local_time
<_Duration
>& __tp
)
111 _TimeZonePtr
{__traits::locate_zone(string_view
{})};
112 } && is_convertible_v
<decltype(std::declval
<_TimeZonePtr
&>() -> to_sys(local_time
<_Duration
>{})),
114 : zoned_time
{__traits::locate_zone(__name
), __tp
} {}
116 _LIBCPP_HIDE_FROM_ABI
zoned_time(_TimeZonePtr __zone
, const local_time
<_Duration
>& __tp
, choose __c
)
117 requires(is_convertible_v
<
118 decltype(std::declval
<_TimeZonePtr
&>() -> to_sys(local_time
<_Duration
>{}, choose::earliest
)),
120 : __zone_
{std::move(__zone
)}, __tp_
{__zone_
->to_sys(__tp
, __c
)} {}
122 _LIBCPP_HIDE_FROM_ABI
zoned_time(string_view __name
, const local_time
<_Duration
>& __tp
, choose __c
)
124 _TimeZonePtr
{__traits::locate_zone(string_view
{})};
125 } && is_convertible_v
<decltype(std::declval
<_TimeZonePtr
&>() -> to_sys(local_time
<_Duration
>{}, choose::earliest
)),
127 : zoned_time
{__traits::locate_zone(__name
), __tp
, __c
} {}
129 template <class _Duration2
, class _TimeZonePtr2
>
130 _LIBCPP_HIDE_FROM_ABI
zoned_time(_TimeZonePtr __zone
, const zoned_time
<_Duration2
, _TimeZonePtr2
>& __zt
)
131 requires is_convertible_v
<sys_time
<_Duration2
>, sys_time
<_Duration
>>
132 : __zone_
{std::move(__zone
)}, __tp_
{__zt
.get_sys_time()} {}
134 // per wording choose has no effect
135 template <class _Duration2
, class _TimeZonePtr2
>
136 _LIBCPP_HIDE_FROM_ABI
zoned_time(_TimeZonePtr __zone
, const zoned_time
<_Duration2
, _TimeZonePtr2
>& __zt
, choose
)
137 requires is_convertible_v
<sys_time
<_Duration2
>, sys_time
<_Duration
>>
138 : __zone_
{std::move(__zone
)}, __tp_
{__zt
.get_sys_time()} {}
140 template <class _Duration2
, class _TimeZonePtr2
>
141 _LIBCPP_HIDE_FROM_ABI
zoned_time(string_view __name
, const zoned_time
<_Duration2
, _TimeZonePtr2
>& __zt
)
143 _TimeZonePtr
{__traits::locate_zone(string_view
{})};
144 } && is_convertible_v
<sys_time
<_Duration2
>, sys_time
<_Duration
>>)
145 : zoned_time
{__traits::locate_zone(__name
), __zt
} {}
147 template <class _Duration2
, class _TimeZonePtr2
>
148 _LIBCPP_HIDE_FROM_ABI
zoned_time(string_view __name
, const zoned_time
<_Duration2
, _TimeZonePtr2
>& __zt
, choose __c
)
150 _TimeZonePtr
{__traits::locate_zone(string_view
{})};
151 } && is_convertible_v
<sys_time
<_Duration2
>, sys_time
<_Duration
>>)
152 : zoned_time
{__traits::locate_zone(__name
), __zt
, __c
} {}
154 _LIBCPP_HIDE_FROM_ABI zoned_time
& operator=(const sys_time
<_Duration
>& __tp
) {
159 _LIBCPP_HIDE_FROM_ABI zoned_time
& operator=(const local_time
<_Duration
>& __tp
) {
160 // TODO TZDB This seems wrong.
161 // Assigning a non-existent or ambiguous time will throw and not satisfy
162 // the post condition. This seems quite odd; I constructed an object with
163 // choose::earliest and that choice is not respected.
164 // what did LEWG do with this.
165 // MSVC STL and libstdc++ behave the same
166 __tp_
= __zone_
->to_sys(__tp
);
170 [[nodiscard
]] _LIBCPP_HIDE_FROM_ABI
operator sys_time
<duration
>() const { return get_sys_time(); }
171 [[nodiscard
]] _LIBCPP_HIDE_FROM_ABI
explicit operator local_time
<duration
>() const { return get_local_time(); }
173 [[nodiscard
]] _LIBCPP_HIDE_FROM_ABI _TimeZonePtr
get_time_zone() const { return __zone_
; }
174 [[nodiscard
]] _LIBCPP_HIDE_FROM_ABI local_time
<duration
> get_local_time() const { return __zone_
->to_local(__tp_
); }
175 [[nodiscard
]] _LIBCPP_HIDE_FROM_ABI sys_time
<duration
> get_sys_time() const { return __tp_
; }
176 [[nodiscard
]] _LIBCPP_HIDE_FROM_ABI sys_info
get_info() const { return __zone_
->get_info(__tp_
); }
179 _TimeZonePtr __zone_
;
180 sys_time
<duration
> __tp_
;
183 zoned_time() -> zoned_time
<seconds
>;
185 template <class _Duration
>
186 zoned_time(sys_time
<_Duration
>) -> zoned_time
<common_type_t
<_Duration
, seconds
>>;
188 template <class _TimeZonePtrOrName
>
189 using __time_zone_representation
=
190 conditional_t
<is_convertible_v
<_TimeZonePtrOrName
, string_view
>,
192 remove_cvref_t
<_TimeZonePtrOrName
>>;
194 template <class _TimeZonePtrOrName
>
195 zoned_time(_TimeZonePtrOrName
&&) -> zoned_time
<seconds
, __time_zone_representation
<_TimeZonePtrOrName
>>;
197 template <class _TimeZonePtrOrName
, class _Duration
>
198 zoned_time(_TimeZonePtrOrName
&&, sys_time
<_Duration
>)
199 -> zoned_time
<common_type_t
<_Duration
, seconds
>, __time_zone_representation
<_TimeZonePtrOrName
>>;
201 template <class _TimeZonePtrOrName
, class _Duration
>
202 zoned_time(_TimeZonePtrOrName
&&, local_time
<_Duration
>, choose
= choose::earliest
)
203 -> zoned_time
<common_type_t
<_Duration
, seconds
>, __time_zone_representation
<_TimeZonePtrOrName
>>;
205 template <class _Duration
, class _TimeZonePtrOrName
, class _TimeZonePtr2
>
206 zoned_time(_TimeZonePtrOrName
&&, zoned_time
<_Duration
, _TimeZonePtr2
>, choose
= choose::earliest
)
207 -> zoned_time
<common_type_t
<_Duration
, seconds
>, __time_zone_representation
<_TimeZonePtrOrName
>>;
209 using zoned_seconds
= zoned_time
<seconds
>;
211 template <class _Duration1
, class _Duration2
, class _TimeZonePtr
>
212 _LIBCPP_HIDE_FROM_ABI
bool
213 operator==(const zoned_time
<_Duration1
, _TimeZonePtr
>& __lhs
, const zoned_time
<_Duration2
, _TimeZonePtr
>& __rhs
) {
214 return __lhs
.get_time_zone() == __rhs
.get_time_zone() && __lhs
.get_sys_time() == __rhs
.get_sys_time();
217 } // namespace chrono
219 # endif // _LIBCPP_STD_VER >= 20 && _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM &&
220 // _LIBCPP_HAS_LOCALIZATION
222 _LIBCPP_END_NAMESPACE_STD
226 #endif // !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB)
228 #endif // _LIBCPP___CHRONO_ZONED_TIME_H