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