1d332d88bSMark de Wever // -*- C++ -*- 2d332d88bSMark de Wever //===----------------------------------------------------------------------===// 3d332d88bSMark de Wever // 4d332d88bSMark de Wever // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 5d332d88bSMark de Wever // See https://llvm.org/LICENSE.txt for license information. 6d332d88bSMark de Wever // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 7d332d88bSMark de Wever // 8d332d88bSMark de Wever //===----------------------------------------------------------------------===// 9d332d88bSMark de Wever 10d332d88bSMark de Wever // For information see https://libcxx.llvm.org/DesignDocs/TimeZone.html 11d332d88bSMark de Wever 12d332d88bSMark de Wever #ifndef _LIBCPP___CHRONO_TIME_ZONE_H 13d332d88bSMark de Wever #define _LIBCPP___CHRONO_TIME_ZONE_H 14d332d88bSMark de Wever 15d332d88bSMark de Wever #include <version> 16d332d88bSMark de Wever // Enable the contents of the header only when libc++ was built with experimental features enabled. 17*24e70e39SNikolas Klauser #if _LIBCPP_HAS_EXPERIMENTAL_TZDB 18d332d88bSMark de Wever 19de736d9cSMark de Wever # include <__chrono/calendar.h> 201fda1776SMark de Wever # include <__chrono/duration.h> 2177116bd7SMark de Wever # include <__chrono/exception.h> 22de736d9cSMark de Wever # include <__chrono/local_info.h> 231fda1776SMark de Wever # include <__chrono/sys_info.h> 241fda1776SMark de Wever # include <__chrono/system_clock.h> 25d332d88bSMark de Wever # include <__compare/strong_order.h> 26d332d88bSMark de Wever # include <__config> 27d332d88bSMark de Wever # include <__memory/unique_ptr.h> 2877116bd7SMark de Wever # include <__type_traits/common_type.h> 29d332d88bSMark de Wever # include <string_view> 30d332d88bSMark de Wever 31d332d88bSMark de Wever # if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 32d332d88bSMark de Wever # pragma GCC system_header 33d332d88bSMark de Wever # endif 34d332d88bSMark de Wever 35d332d88bSMark de Wever _LIBCPP_PUSH_MACROS 36d332d88bSMark de Wever # include <__undef_macros> 37d332d88bSMark de Wever 38d332d88bSMark de Wever _LIBCPP_BEGIN_NAMESPACE_STD 39d332d88bSMark de Wever 40c6f3b7bcSNikolas Klauser # if _LIBCPP_STD_VER >= 20 && _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM && _LIBCPP_HAS_LOCALIZATION 41d332d88bSMark de Wever 42d332d88bSMark de Wever namespace chrono { 43d332d88bSMark de Wever 4487cedbecSMark de Wever enum class choose { earliest, latest }; 4587cedbecSMark de Wever 46d332d88bSMark de Wever class _LIBCPP_AVAILABILITY_TZDB time_zone { 47d332d88bSMark de Wever _LIBCPP_HIDE_FROM_ABI time_zone() = default; 48d332d88bSMark de Wever 49d332d88bSMark de Wever public: 50d332d88bSMark de Wever class __impl; // public so it can be used by make_unique. 51d332d88bSMark de Wever 52d332d88bSMark de Wever // The "constructor". 53d332d88bSMark de Wever // 54d332d88bSMark de Wever // The default constructor is private to avoid the constructor from being 55d332d88bSMark de Wever // part of the ABI. Instead use an __ugly_named function as an ABI interface, 56d332d88bSMark de Wever // since that gives us the ability to change it in the future. 57d332d88bSMark de Wever [[nodiscard]] _LIBCPP_EXPORTED_FROM_ABI static time_zone __create(unique_ptr<__impl>&& __p); 58d332d88bSMark de Wever 59d332d88bSMark de Wever _LIBCPP_EXPORTED_FROM_ABI ~time_zone(); 60d332d88bSMark de Wever 61d332d88bSMark de Wever _LIBCPP_HIDE_FROM_ABI time_zone(time_zone&&) = default; 62d332d88bSMark de Wever _LIBCPP_HIDE_FROM_ABI time_zone& operator=(time_zone&&) = default; 63d332d88bSMark de Wever 6483bc7b57SNikolas Klauser [[nodiscard]] _LIBCPP_HIDE_FROM_ABI string_view name() const noexcept { return __name(); } 65d332d88bSMark de Wever 661fda1776SMark de Wever template <class _Duration> 6783bc7b57SNikolas Klauser [[nodiscard]] _LIBCPP_HIDE_FROM_ABI sys_info get_info(const sys_time<_Duration>& __time) const { 681fda1776SMark de Wever return __get_info(chrono::time_point_cast<seconds>(__time)); 691fda1776SMark de Wever } 701fda1776SMark de Wever 71de736d9cSMark de Wever template <class _Duration> 72de736d9cSMark de Wever [[nodiscard]] _LIBCPP_HIDE_FROM_ABI local_info get_info(const local_time<_Duration>& __time) const { 73de736d9cSMark de Wever return __get_info(chrono::time_point_cast<seconds>(__time)); 74de736d9cSMark de Wever } 75de736d9cSMark de Wever 7677116bd7SMark de Wever // We don't apply nodiscard here since this function throws on many inputs, 7777116bd7SMark de Wever // so it could be used as a validation. 7877116bd7SMark de Wever template <class _Duration> 7977116bd7SMark de Wever _LIBCPP_HIDE_FROM_ABI sys_time<common_type_t<_Duration, seconds>> to_sys(const local_time<_Duration>& __time) const { 8077116bd7SMark de Wever local_info __info = get_info(__time); 8177116bd7SMark de Wever switch (__info.result) { 8277116bd7SMark de Wever case local_info::unique: 8377116bd7SMark de Wever return sys_time<common_type_t<_Duration, seconds>>{__time.time_since_epoch() - __info.first.offset}; 8477116bd7SMark de Wever 8577116bd7SMark de Wever case local_info::nonexistent: 8677116bd7SMark de Wever chrono::__throw_nonexistent_local_time(__time, __info); 8777116bd7SMark de Wever 8877116bd7SMark de Wever case local_info::ambiguous: 8977116bd7SMark de Wever chrono::__throw_ambiguous_local_time(__time, __info); 9077116bd7SMark de Wever } 9177116bd7SMark de Wever 9277116bd7SMark de Wever // TODO TZDB The Standard does not specify anything in these cases. 9377116bd7SMark de Wever _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( 9477116bd7SMark de Wever __info.result != -1, "cannot convert the local time; it would be before the minimum system clock value"); 9577116bd7SMark de Wever _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( 9677116bd7SMark de Wever __info.result != -2, "cannot convert the local time; it would be after the maximum system clock value"); 9777116bd7SMark de Wever 9877116bd7SMark de Wever return {}; 9977116bd7SMark de Wever } 10077116bd7SMark de Wever 10187cedbecSMark de Wever template <class _Duration> 10287cedbecSMark de Wever [[nodiscard]] _LIBCPP_HIDE_FROM_ABI sys_time<common_type_t<_Duration, seconds>> 10387cedbecSMark de Wever to_sys(const local_time<_Duration>& __time, choose __z) const { 10487cedbecSMark de Wever local_info __info = get_info(__time); 10587cedbecSMark de Wever switch (__info.result) { 10687cedbecSMark de Wever case local_info::unique: 10787cedbecSMark de Wever case local_info::nonexistent: // first and second are the same 10887cedbecSMark de Wever return sys_time<common_type_t<_Duration, seconds>>{__time.time_since_epoch() - __info.first.offset}; 10987cedbecSMark de Wever 11087cedbecSMark de Wever case local_info::ambiguous: 11187cedbecSMark de Wever switch (__z) { 11287cedbecSMark de Wever case choose::earliest: 11387cedbecSMark de Wever return sys_time<common_type_t<_Duration, seconds>>{__time.time_since_epoch() - __info.first.offset}; 11487cedbecSMark de Wever 11587cedbecSMark de Wever case choose::latest: 11687cedbecSMark de Wever return sys_time<common_type_t<_Duration, seconds>>{__time.time_since_epoch() - __info.second.offset}; 11787cedbecSMark de Wever 11887cedbecSMark de Wever // Note a value out of bounds is not specified. 11987cedbecSMark de Wever } 12087cedbecSMark de Wever } 12187cedbecSMark de Wever 12287cedbecSMark de Wever // TODO TZDB The standard does not specify anything in these cases. 12387cedbecSMark de Wever _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( 12487cedbecSMark de Wever __info.result != -1, "cannot convert the local time; it would be before the minimum system clock value"); 12587cedbecSMark de Wever _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( 12687cedbecSMark de Wever __info.result != -2, "cannot convert the local time; it would be after the maximum system clock value"); 12787cedbecSMark de Wever 12887cedbecSMark de Wever return {}; 12987cedbecSMark de Wever } 13087cedbecSMark de Wever 131da03175cSMark de Wever template <class _Duration> 132da03175cSMark de Wever [[nodiscard]] _LIBCPP_HIDE_FROM_ABI local_time<common_type_t<_Duration, seconds>> 133da03175cSMark de Wever to_local(const sys_time<_Duration>& __time) const { 134da03175cSMark de Wever using _Dp = common_type_t<_Duration, seconds>; 135da03175cSMark de Wever 136da03175cSMark de Wever sys_info __info = get_info(__time); 137da03175cSMark de Wever 138da03175cSMark de Wever _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( 139da03175cSMark de Wever __info.offset >= chrono::seconds{0} || __time.time_since_epoch() >= _Dp::min() - __info.offset, 140da03175cSMark de Wever "cannot convert the system time; it would be before the minimum local clock value"); 141da03175cSMark de Wever 142da03175cSMark de Wever _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( 143da03175cSMark de Wever __info.offset <= chrono::seconds{0} || __time.time_since_epoch() <= _Dp::max() - __info.offset, 144da03175cSMark de Wever "cannot convert the system time; it would be after the maximum local clock value"); 145da03175cSMark de Wever 146da03175cSMark de Wever return local_time<_Dp>{__time.time_since_epoch() + __info.offset}; 147da03175cSMark de Wever } 148da03175cSMark de Wever 149d332d88bSMark de Wever [[nodiscard]] _LIBCPP_HIDE_FROM_ABI const __impl& __implementation() const noexcept { return *__impl_; } 150d332d88bSMark de Wever 151d332d88bSMark de Wever private: 152d332d88bSMark de Wever [[nodiscard]] _LIBCPP_EXPORTED_FROM_ABI string_view __name() const noexcept; 1531fda1776SMark de Wever 1541fda1776SMark de Wever [[nodiscard]] _LIBCPP_AVAILABILITY_TZDB _LIBCPP_EXPORTED_FROM_ABI sys_info __get_info(sys_seconds __time) const; 155de736d9cSMark de Wever [[nodiscard]] _LIBCPP_AVAILABILITY_TZDB _LIBCPP_EXPORTED_FROM_ABI local_info __get_info(local_seconds __time) const; 1561fda1776SMark de Wever 157d332d88bSMark de Wever unique_ptr<__impl> __impl_; 158d332d88bSMark de Wever }; 159d332d88bSMark de Wever 16083bc7b57SNikolas Klauser [[nodiscard]] _LIBCPP_AVAILABILITY_TZDB _LIBCPP_HIDE_FROM_ABI inline bool 161d332d88bSMark de Wever operator==(const time_zone& __x, const time_zone& __y) noexcept { 162d332d88bSMark de Wever return __x.name() == __y.name(); 163d332d88bSMark de Wever } 164d332d88bSMark de Wever 16583bc7b57SNikolas Klauser [[nodiscard]] _LIBCPP_AVAILABILITY_TZDB _LIBCPP_HIDE_FROM_ABI inline strong_ordering 166d332d88bSMark de Wever operator<=>(const time_zone& __x, const time_zone& __y) noexcept { 167d332d88bSMark de Wever return __x.name() <=> __y.name(); 168d332d88bSMark de Wever } 169d332d88bSMark de Wever 170d332d88bSMark de Wever } // namespace chrono 171d332d88bSMark de Wever 172c6f3b7bcSNikolas Klauser # endif // _LIBCPP_STD_VER >= 20 && _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM && 173c6f3b7bcSNikolas Klauser // _LIBCPP_HAS_LOCALIZATION 174d332d88bSMark de Wever 175d332d88bSMark de Wever _LIBCPP_END_NAMESPACE_STD 176d332d88bSMark de Wever 177d332d88bSMark de Wever _LIBCPP_POP_MACROS 178d332d88bSMark de Wever 179*24e70e39SNikolas Klauser #endif // _LIBCPP_HAS_EXPERIMENTAL_TZDB 180d332d88bSMark de Wever 181d332d88bSMark de Wever #endif // _LIBCPP___CHRONO_TIME_ZONE_H 182