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_TIME_ZONE_H 13*0fca6ea1SDimitry Andric #define _LIBCPP___CHRONO_TIME_ZONE_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/exception.h> 22*0fca6ea1SDimitry Andric # include <__chrono/local_info.h> 23*0fca6ea1SDimitry Andric # include <__chrono/sys_info.h> 24*0fca6ea1SDimitry Andric # include <__chrono/system_clock.h> 25*0fca6ea1SDimitry Andric # include <__compare/strong_order.h> 26*0fca6ea1SDimitry Andric # include <__config> 27*0fca6ea1SDimitry Andric # include <__memory/unique_ptr.h> 28*0fca6ea1SDimitry Andric # include <__type_traits/common_type.h> 29*0fca6ea1SDimitry Andric # include <string_view> 30*0fca6ea1SDimitry Andric 31*0fca6ea1SDimitry Andric # if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 32*0fca6ea1SDimitry Andric # pragma GCC system_header 33*0fca6ea1SDimitry Andric # endif 34*0fca6ea1SDimitry Andric 35*0fca6ea1SDimitry Andric _LIBCPP_PUSH_MACROS 36*0fca6ea1SDimitry Andric # include <__undef_macros> 37*0fca6ea1SDimitry Andric 38*0fca6ea1SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD 39*0fca6ea1SDimitry Andric 40*0fca6ea1SDimitry Andric # if _LIBCPP_STD_VER >= 20 && !defined(_LIBCPP_HAS_NO_TIME_ZONE_DATABASE) && !defined(_LIBCPP_HAS_NO_FILESYSTEM) && \ 41*0fca6ea1SDimitry Andric !defined(_LIBCPP_HAS_NO_LOCALIZATION) 42*0fca6ea1SDimitry Andric 43*0fca6ea1SDimitry Andric namespace chrono { 44*0fca6ea1SDimitry Andric 45*0fca6ea1SDimitry Andric enum class choose { earliest, latest }; 46*0fca6ea1SDimitry Andric 47*0fca6ea1SDimitry Andric class _LIBCPP_AVAILABILITY_TZDB time_zone { 48*0fca6ea1SDimitry Andric _LIBCPP_HIDE_FROM_ABI time_zone() = default; 49*0fca6ea1SDimitry Andric 50*0fca6ea1SDimitry Andric public: 51*0fca6ea1SDimitry Andric class __impl; // public so it can be used by make_unique. 52*0fca6ea1SDimitry Andric 53*0fca6ea1SDimitry Andric // The "constructor". 54*0fca6ea1SDimitry Andric // 55*0fca6ea1SDimitry Andric // The default constructor is private to avoid the constructor from being 56*0fca6ea1SDimitry Andric // part of the ABI. Instead use an __ugly_named function as an ABI interface, 57*0fca6ea1SDimitry Andric // since that gives us the ability to change it in the future. 58*0fca6ea1SDimitry Andric [[nodiscard]] _LIBCPP_EXPORTED_FROM_ABI static time_zone __create(unique_ptr<__impl>&& __p); 59*0fca6ea1SDimitry Andric 60*0fca6ea1SDimitry Andric _LIBCPP_EXPORTED_FROM_ABI ~time_zone(); 61*0fca6ea1SDimitry Andric 62*0fca6ea1SDimitry Andric _LIBCPP_HIDE_FROM_ABI time_zone(time_zone&&) = default; 63*0fca6ea1SDimitry Andric _LIBCPP_HIDE_FROM_ABI time_zone& operator=(time_zone&&) = default; 64*0fca6ea1SDimitry Andric 65*0fca6ea1SDimitry Andric [[nodiscard]] _LIBCPP_HIDE_FROM_ABI string_view name() const noexcept { return __name(); } 66*0fca6ea1SDimitry Andric 67*0fca6ea1SDimitry Andric template <class _Duration> 68*0fca6ea1SDimitry Andric [[nodiscard]] _LIBCPP_HIDE_FROM_ABI sys_info get_info(const sys_time<_Duration>& __time) const { 69*0fca6ea1SDimitry Andric return __get_info(chrono::time_point_cast<seconds>(__time)); 70*0fca6ea1SDimitry Andric } 71*0fca6ea1SDimitry Andric 72*0fca6ea1SDimitry Andric template <class _Duration> 73*0fca6ea1SDimitry Andric [[nodiscard]] _LIBCPP_HIDE_FROM_ABI local_info get_info(const local_time<_Duration>& __time) const { 74*0fca6ea1SDimitry Andric return __get_info(chrono::time_point_cast<seconds>(__time)); 75*0fca6ea1SDimitry Andric } 76*0fca6ea1SDimitry Andric 77*0fca6ea1SDimitry Andric // We don't apply nodiscard here since this function throws on many inputs, 78*0fca6ea1SDimitry Andric // so it could be used as a validation. 79*0fca6ea1SDimitry Andric template <class _Duration> 80*0fca6ea1SDimitry Andric _LIBCPP_HIDE_FROM_ABI sys_time<common_type_t<_Duration, seconds>> to_sys(const local_time<_Duration>& __time) const { 81*0fca6ea1SDimitry Andric local_info __info = get_info(__time); 82*0fca6ea1SDimitry Andric switch (__info.result) { 83*0fca6ea1SDimitry Andric case local_info::unique: 84*0fca6ea1SDimitry Andric return sys_time<common_type_t<_Duration, seconds>>{__time.time_since_epoch() - __info.first.offset}; 85*0fca6ea1SDimitry Andric 86*0fca6ea1SDimitry Andric case local_info::nonexistent: 87*0fca6ea1SDimitry Andric chrono::__throw_nonexistent_local_time(__time, __info); 88*0fca6ea1SDimitry Andric 89*0fca6ea1SDimitry Andric case local_info::ambiguous: 90*0fca6ea1SDimitry Andric chrono::__throw_ambiguous_local_time(__time, __info); 91*0fca6ea1SDimitry Andric } 92*0fca6ea1SDimitry Andric 93*0fca6ea1SDimitry Andric // TODO TZDB The Standard does not specify anything in these cases. 94*0fca6ea1SDimitry Andric _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( 95*0fca6ea1SDimitry Andric __info.result != -1, "cannot convert the local time; it would be before the minimum system clock value"); 96*0fca6ea1SDimitry Andric _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( 97*0fca6ea1SDimitry Andric __info.result != -2, "cannot convert the local time; it would be after the maximum system clock value"); 98*0fca6ea1SDimitry Andric 99*0fca6ea1SDimitry Andric return {}; 100*0fca6ea1SDimitry Andric } 101*0fca6ea1SDimitry Andric 102*0fca6ea1SDimitry Andric template <class _Duration> 103*0fca6ea1SDimitry Andric [[nodiscard]] _LIBCPP_HIDE_FROM_ABI sys_time<common_type_t<_Duration, seconds>> 104*0fca6ea1SDimitry Andric to_sys(const local_time<_Duration>& __time, choose __z) const { 105*0fca6ea1SDimitry Andric local_info __info = get_info(__time); 106*0fca6ea1SDimitry Andric switch (__info.result) { 107*0fca6ea1SDimitry Andric case local_info::unique: 108*0fca6ea1SDimitry Andric case local_info::nonexistent: // first and second are the same 109*0fca6ea1SDimitry Andric return sys_time<common_type_t<_Duration, seconds>>{__time.time_since_epoch() - __info.first.offset}; 110*0fca6ea1SDimitry Andric 111*0fca6ea1SDimitry Andric case local_info::ambiguous: 112*0fca6ea1SDimitry Andric switch (__z) { 113*0fca6ea1SDimitry Andric case choose::earliest: 114*0fca6ea1SDimitry Andric return sys_time<common_type_t<_Duration, seconds>>{__time.time_since_epoch() - __info.first.offset}; 115*0fca6ea1SDimitry Andric 116*0fca6ea1SDimitry Andric case choose::latest: 117*0fca6ea1SDimitry Andric return sys_time<common_type_t<_Duration, seconds>>{__time.time_since_epoch() - __info.second.offset}; 118*0fca6ea1SDimitry Andric 119*0fca6ea1SDimitry Andric // Note a value out of bounds is not specified. 120*0fca6ea1SDimitry Andric } 121*0fca6ea1SDimitry Andric } 122*0fca6ea1SDimitry Andric 123*0fca6ea1SDimitry Andric // TODO TZDB The standard does not specify anything in these cases. 124*0fca6ea1SDimitry Andric _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( 125*0fca6ea1SDimitry Andric __info.result != -1, "cannot convert the local time; it would be before the minimum system clock value"); 126*0fca6ea1SDimitry Andric _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( 127*0fca6ea1SDimitry Andric __info.result != -2, "cannot convert the local time; it would be after the maximum system clock value"); 128*0fca6ea1SDimitry Andric 129*0fca6ea1SDimitry Andric return {}; 130*0fca6ea1SDimitry Andric } 131*0fca6ea1SDimitry Andric 132*0fca6ea1SDimitry Andric template <class _Duration> 133*0fca6ea1SDimitry Andric [[nodiscard]] _LIBCPP_HIDE_FROM_ABI local_time<common_type_t<_Duration, seconds>> 134*0fca6ea1SDimitry Andric to_local(const sys_time<_Duration>& __time) const { 135*0fca6ea1SDimitry Andric using _Dp = common_type_t<_Duration, seconds>; 136*0fca6ea1SDimitry Andric 137*0fca6ea1SDimitry Andric sys_info __info = get_info(__time); 138*0fca6ea1SDimitry Andric 139*0fca6ea1SDimitry Andric _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( 140*0fca6ea1SDimitry Andric __info.offset >= chrono::seconds{0} || __time.time_since_epoch() >= _Dp::min() - __info.offset, 141*0fca6ea1SDimitry Andric "cannot convert the system time; it would be before the minimum local clock value"); 142*0fca6ea1SDimitry Andric 143*0fca6ea1SDimitry Andric _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( 144*0fca6ea1SDimitry Andric __info.offset <= chrono::seconds{0} || __time.time_since_epoch() <= _Dp::max() - __info.offset, 145*0fca6ea1SDimitry Andric "cannot convert the system time; it would be after the maximum local clock value"); 146*0fca6ea1SDimitry Andric 147*0fca6ea1SDimitry Andric return local_time<_Dp>{__time.time_since_epoch() + __info.offset}; 148*0fca6ea1SDimitry Andric } 149*0fca6ea1SDimitry Andric 150*0fca6ea1SDimitry Andric [[nodiscard]] _LIBCPP_HIDE_FROM_ABI const __impl& __implementation() const noexcept { return *__impl_; } 151*0fca6ea1SDimitry Andric 152*0fca6ea1SDimitry Andric private: 153*0fca6ea1SDimitry Andric [[nodiscard]] _LIBCPP_EXPORTED_FROM_ABI string_view __name() const noexcept; 154*0fca6ea1SDimitry Andric 155*0fca6ea1SDimitry Andric [[nodiscard]] _LIBCPP_AVAILABILITY_TZDB _LIBCPP_EXPORTED_FROM_ABI sys_info __get_info(sys_seconds __time) const; 156*0fca6ea1SDimitry Andric [[nodiscard]] _LIBCPP_AVAILABILITY_TZDB _LIBCPP_EXPORTED_FROM_ABI local_info __get_info(local_seconds __time) const; 157*0fca6ea1SDimitry Andric 158*0fca6ea1SDimitry Andric unique_ptr<__impl> __impl_; 159*0fca6ea1SDimitry Andric }; 160*0fca6ea1SDimitry Andric 161*0fca6ea1SDimitry Andric [[nodiscard]] _LIBCPP_AVAILABILITY_TZDB _LIBCPP_HIDE_FROM_ABI inline bool 162*0fca6ea1SDimitry Andric operator==(const time_zone& __x, const time_zone& __y) noexcept { 163*0fca6ea1SDimitry Andric return __x.name() == __y.name(); 164*0fca6ea1SDimitry Andric } 165*0fca6ea1SDimitry Andric 166*0fca6ea1SDimitry Andric [[nodiscard]] _LIBCPP_AVAILABILITY_TZDB _LIBCPP_HIDE_FROM_ABI inline strong_ordering 167*0fca6ea1SDimitry Andric operator<=>(const time_zone& __x, const time_zone& __y) noexcept { 168*0fca6ea1SDimitry Andric return __x.name() <=> __y.name(); 169*0fca6ea1SDimitry Andric } 170*0fca6ea1SDimitry Andric 171*0fca6ea1SDimitry Andric } // namespace chrono 172*0fca6ea1SDimitry Andric 173*0fca6ea1SDimitry Andric # endif // _LIBCPP_STD_VER >= 20 && !defined(_LIBCPP_HAS_NO_TIME_ZONE_DATABASE) && !defined(_LIBCPP_HAS_NO_FILESYSTEM) 174*0fca6ea1SDimitry Andric // && !defined(_LIBCPP_HAS_NO_LOCALIZATION) 175*0fca6ea1SDimitry Andric 176*0fca6ea1SDimitry Andric _LIBCPP_END_NAMESPACE_STD 177*0fca6ea1SDimitry Andric 178*0fca6ea1SDimitry Andric _LIBCPP_POP_MACROS 179*0fca6ea1SDimitry Andric 180*0fca6ea1SDimitry Andric #endif // !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB) 181*0fca6ea1SDimitry Andric 182*0fca6ea1SDimitry Andric #endif // _LIBCPP___CHRONO_TIME_ZONE_H 183