xref: /freebsd/contrib/llvm-project/libcxx/include/__chrono/tai_clock.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
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 #ifndef _LIBCPP___CHRONO_TAI_CLOCK_H
11 #define _LIBCPP___CHRONO_TAI_CLOCK_H
12 
13 #include <version>
14 // Enable the contents of the header only when libc++ was built with experimental features enabled.
15 #if _LIBCPP_HAS_EXPERIMENTAL_TZDB
16 
17 #  include <__assert>
18 #  include <__chrono/duration.h>
19 #  include <__chrono/time_point.h>
20 #  include <__chrono/utc_clock.h>
21 #  include <__config>
22 #  include <__type_traits/common_type.h>
23 
24 #  if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
25 #    pragma GCC system_header
26 #  endif
27 
28 _LIBCPP_PUSH_MACROS
29 #  include <__undef_macros>
30 
31 _LIBCPP_BEGIN_NAMESPACE_STD
32 
33 #  if _LIBCPP_STD_VER >= 20 && _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM && _LIBCPP_HAS_LOCALIZATION
34 
35 namespace chrono {
36 
37 class tai_clock;
38 
39 template <class _Duration>
40 using tai_time    = time_point<tai_clock, _Duration>;
41 using tai_seconds = tai_time<seconds>;
42 
43 // [time.clock.tai.overview]/1
44 //    The clock tai_clock measures seconds since 1958-01-01 00:00:00 and is
45 //    offset 10s ahead of UTC at this date. That is, 1958-01-01 00:00:00 TAI is
46 //    equivalent to 1957-12-31 23:59:50 UTC. Leap seconds are not inserted into
47 //    TAI. Therefore every time a leap second is inserted into UTC, UTC shifts
48 //    another second with respect to TAI. For example by 2000-01-01 there had
49 //    been 22 positive and 0 negative leap seconds inserted so 2000-01-01
50 //    00:00:00 UTC is equivalent to 2000-01-01 00:00:32 TAI (22s plus the
51 //    initial 10s offset).
52 //
53 // Note this does not specify what the UTC offset before 1958-01-01 00:00:00
54 // TAI is, nor does it follow the "real" TAI clock between 1958-01-01 and the
55 // start of the UTC epoch. So while the member functions are fully specified in
56 // the standard, they do not technically follow the "real-world" TAI clock with
57 // 100% accuracy.
58 //
59 // https://koka-lang.github.io/koka/doc/std_time_utc.html contains more
60 // information and references.
61 class tai_clock {
62 public:
63   using rep                       = utc_clock::rep;
64   using period                    = utc_clock::period;
65   using duration                  = chrono::duration<rep, period>;
66   using time_point                = chrono::time_point<tai_clock>;
67   static constexpr bool is_steady = false; // The utc_clock is not steady.
68 
69   // The static difference between UTC and TAI time.
70   static constexpr chrono::seconds __offset{378691210};
71 
now()72   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static time_point now() { return from_utc(utc_clock::now()); }
73 
74   template <class _Duration>
75   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static utc_time<common_type_t<_Duration, seconds>>
to_utc(const tai_time<_Duration> & __time)76   to_utc(const tai_time<_Duration>& __time) noexcept {
77     using _Rp                    = common_type_t<_Duration, seconds>;
78     _Duration __time_since_epoch = __time.time_since_epoch();
79     _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(__time_since_epoch >= utc_time<_Rp>::min().time_since_epoch() + __offset,
80                                           "the TAI to UTC conversion would underflow");
81 
82     return utc_time<_Rp>{__time_since_epoch - __offset};
83   }
84 
85   template <class _Duration>
86   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static tai_time<common_type_t<_Duration, seconds>>
from_utc(const utc_time<_Duration> & __time)87   from_utc(const utc_time<_Duration>& __time) noexcept {
88     using _Rp                    = common_type_t<_Duration, seconds>;
89     _Duration __time_since_epoch = __time.time_since_epoch();
90     _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(__time_since_epoch <= utc_time<_Rp>::max().time_since_epoch() - __offset,
91                                           "the UTC to TAI conversion would overflow");
92 
93     return tai_time<_Rp>{__time_since_epoch + __offset};
94   }
95 };
96 
97 } // namespace chrono
98 
99 #  endif // _LIBCPP_STD_VER >= 20 && _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM &&
100          // _LIBCPP_HAS_LOCALIZATION
101 
102 _LIBCPP_END_NAMESPACE_STD
103 
104 _LIBCPP_POP_MACROS
105 
106 #endif // _LIBCPP_HAS_EXPERIMENTAL_TZDB
107 
108 #endif // _LIBCPP___CHRONO_TAI_CLOCK_H
109