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