xref: /freebsd-src/contrib/llvm-project/libcxx/include/__chrono/time_zone.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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