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