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 _LIBCPP_HAS_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 <__concepts/constructible.h> 26 # include <__config> 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> 33 34 # if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 35 # pragma GCC system_header 36 # endif 37 38 _LIBCPP_PUSH_MACROS 39 # include <__undef_macros> 40 41 _LIBCPP_BEGIN_NAMESPACE_STD 42 43 # if _LIBCPP_STD_VER >= 20 && _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM && _LIBCPP_HAS_LOCALIZATION 44 45 namespace chrono { 46 47 template <class> 48 struct zoned_traits {}; 49 50 template <> 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); 55 } 56 }; 57 58 template <class _Duration, class _TimeZonePtr = const time_zone*> 59 class zoned_time { 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"); 63 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 _LIBCPP_NODEBUG = zoned_traits<_TimeZonePtr>; 70 71 public: 72 using duration = common_type_t<_Duration, seconds>; 73 74 _LIBCPP_HIDE_FROM_ABI zoned_time() 75 requires requires { __traits::default_zone(); } 76 : __zone_{__traits::default_zone()}, __tp_{} {} 77 78 _LIBCPP_HIDE_FROM_ABI zoned_time(const zoned_time&) = default; 79 _LIBCPP_HIDE_FROM_ABI zoned_time& operator=(const zoned_time&) = default; 80 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} {} 84 85 _LIBCPP_HIDE_FROM_ABI explicit zoned_time(_TimeZonePtr __zone) : __zone_{std::move(__zone)}, __tp_{} {} 86 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_{} {} 91 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()} {} 96 97 _LIBCPP_HIDE_FROM_ABI zoned_time(_TimeZonePtr __zone, const sys_time<_Duration>& __tp) 98 : __zone_{std::move(__zone)}, __tp_{__tp} {} 99 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} {} 103 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>{})), 106 sys_time<duration>>) 107 : __zone_{std::move(__zone)}, __tp_{__zone_->to_sys(__tp)} {} 108 109 _LIBCPP_HIDE_FROM_ABI zoned_time(string_view __name, const local_time<_Duration>& __tp) 110 requires(requires { 111 _TimeZonePtr{__traits::locate_zone(string_view{})}; 112 } && is_convertible_v<decltype(std::declval<_TimeZonePtr&>() -> to_sys(local_time<_Duration>{})), 113 sys_time<duration>>) 114 : zoned_time{__traits::locate_zone(__name), __tp} {} 115 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)), 119 sys_time<duration>>) 120 : __zone_{std::move(__zone)}, __tp_{__zone_->to_sys(__tp, __c)} {} 121 122 _LIBCPP_HIDE_FROM_ABI zoned_time(string_view __name, const local_time<_Duration>& __tp, choose __c) 123 requires(requires { 124 _TimeZonePtr{__traits::locate_zone(string_view{})}; 125 } && is_convertible_v<decltype(std::declval<_TimeZonePtr&>() -> to_sys(local_time<_Duration>{}, choose::earliest)), 126 sys_time<duration>>) 127 : zoned_time{__traits::locate_zone(__name), __tp, __c} {} 128 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()} {} 133 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()} {} 139 140 template <class _Duration2, class _TimeZonePtr2> 141 _LIBCPP_HIDE_FROM_ABI zoned_time(string_view __name, const zoned_time<_Duration2, _TimeZonePtr2>& __zt) 142 requires(requires { 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} {} 146 147 template <class _Duration2, class _TimeZonePtr2> 148 _LIBCPP_HIDE_FROM_ABI zoned_time(string_view __name, const zoned_time<_Duration2, _TimeZonePtr2>& __zt, choose __c) 149 requires(requires { 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} {} 153 154 _LIBCPP_HIDE_FROM_ABI zoned_time& operator=(const sys_time<_Duration>& __tp) { 155 __tp_ = __tp; 156 return *this; 157 } 158 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); 167 return *this; 168 } 169 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(); } 172 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_); } 177 178 private: 179 _TimeZonePtr __zone_; 180 sys_time<duration> __tp_; 181 }; 182 183 zoned_time() -> zoned_time<seconds>; 184 185 template <class _Duration> 186 zoned_time(sys_time<_Duration>) -> zoned_time<common_type_t<_Duration, seconds>>; 187 188 template <class _TimeZonePtrOrName> 189 using __time_zone_representation _LIBCPP_NODEBUG = 190 conditional_t<is_convertible_v<_TimeZonePtrOrName, string_view>, 191 const time_zone*, 192 remove_cvref_t<_TimeZonePtrOrName>>; 193 194 template <class _TimeZonePtrOrName> 195 zoned_time(_TimeZonePtrOrName&&) -> zoned_time<seconds, __time_zone_representation<_TimeZonePtrOrName>>; 196 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>>; 200 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>>; 204 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>>; 208 209 using zoned_seconds = zoned_time<seconds>; 210 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(); 215 } 216 217 } // namespace chrono 218 219 # endif // _LIBCPP_STD_VER >= 20 && _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM && 220 // _LIBCPP_HAS_LOCALIZATION 221 222 _LIBCPP_END_NAMESPACE_STD 223 224 _LIBCPP_POP_MACROS 225 226 #endif // _LIBCPP_HAS_EXPERIMENTAL_TZDB 227 228 #endif // _LIBCPP___CHRONO_ZONED_TIME_H 229