xref: /llvm-project/libcxx/include/__chrono/time_zone.h (revision 24e70e3930724ce499ad05d669bfbc4423c542e0)
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