xref: /llvm-project/libcxx/include/__chrono/utc_clock.h (revision 3b30f20c60d020e43f5700dae68cf1080158b725)
10cd794d4SMark de Wever // -*- C++ -*-
20cd794d4SMark de Wever //===----------------------------------------------------------------------===//
30cd794d4SMark de Wever //
40cd794d4SMark de Wever // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
50cd794d4SMark de Wever // See https://llvm.org/LICENSE.txt for license information.
60cd794d4SMark de Wever // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
70cd794d4SMark de Wever //
80cd794d4SMark de Wever //===----------------------------------------------------------------------===//
90cd794d4SMark de Wever 
100cd794d4SMark de Wever #ifndef _LIBCPP___CHRONO_UTC_CLOCK_H
110cd794d4SMark de Wever #define _LIBCPP___CHRONO_UTC_CLOCK_H
120cd794d4SMark de Wever 
130cd794d4SMark de Wever #include <version>
140cd794d4SMark de Wever // Enable the contents of the header only when libc++ was built with experimental features enabled.
15*3b30f20cSMark de Wever #if _LIBCPP_HAS_EXPERIMENTAL_TZDB
160cd794d4SMark de Wever 
170cd794d4SMark de Wever #  include <__chrono/duration.h>
180cd794d4SMark de Wever #  include <__chrono/leap_second.h>
190cd794d4SMark de Wever #  include <__chrono/system_clock.h>
200cd794d4SMark de Wever #  include <__chrono/time_point.h>
210cd794d4SMark de Wever #  include <__chrono/tzdb.h>
220cd794d4SMark de Wever #  include <__chrono/tzdb_list.h>
230cd794d4SMark de Wever #  include <__config>
240cd794d4SMark de Wever #  include <__type_traits/common_type.h>
250cd794d4SMark de Wever 
260cd794d4SMark de Wever #  if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
270cd794d4SMark de Wever #    pragma GCC system_header
280cd794d4SMark de Wever #  endif
290cd794d4SMark de Wever 
300cd794d4SMark de Wever _LIBCPP_BEGIN_NAMESPACE_STD
310cd794d4SMark de Wever 
320cd794d4SMark de Wever #  if _LIBCPP_STD_VER >= 20 && _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM && _LIBCPP_HAS_LOCALIZATION
330cd794d4SMark de Wever 
340cd794d4SMark de Wever namespace chrono {
350cd794d4SMark de Wever 
360cd794d4SMark de Wever class utc_clock;
370cd794d4SMark de Wever 
380cd794d4SMark de Wever template <class _Duration>
390cd794d4SMark de Wever using utc_time    = time_point<utc_clock, _Duration>;
400cd794d4SMark de Wever using utc_seconds = utc_time<seconds>;
410cd794d4SMark de Wever 
420cd794d4SMark de Wever class utc_clock {
430cd794d4SMark de Wever public:
440cd794d4SMark de Wever   using rep                       = system_clock::rep;
450cd794d4SMark de Wever   using period                    = system_clock::period;
460cd794d4SMark de Wever   using duration                  = chrono::duration<rep, period>;
470cd794d4SMark de Wever   using time_point                = chrono::time_point<utc_clock>;
480cd794d4SMark de Wever   static constexpr bool is_steady = false; // The system_clock is not steady.
490cd794d4SMark de Wever 
500cd794d4SMark de Wever   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static time_point now() { return from_sys(system_clock::now()); }
510cd794d4SMark de Wever 
520cd794d4SMark de Wever   template <class _Duration>
530cd794d4SMark de Wever   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static sys_time<common_type_t<_Duration, seconds>>
540cd794d4SMark de Wever   to_sys(const utc_time<_Duration>& __time);
550cd794d4SMark de Wever 
560cd794d4SMark de Wever   template <class _Duration>
570cd794d4SMark de Wever   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static utc_time<common_type_t<_Duration, seconds>>
580cd794d4SMark de Wever   from_sys(const sys_time<_Duration>& __time) {
590cd794d4SMark de Wever     using _Rp = utc_time<common_type_t<_Duration, seconds>>;
600cd794d4SMark de Wever     // TODO TZDB investigate optimizations.
610cd794d4SMark de Wever     //
620cd794d4SMark de Wever     // The leap second database stores all transitions, this mean to calculate
630cd794d4SMark de Wever     // the current number of leap seconds the code needs to iterate over all
640cd794d4SMark de Wever     // leap seconds to accumulate the sum. Then the sum can be used to determine
650cd794d4SMark de Wever     // the sys_time. Accessing the database involves acquiring a mutex.
660cd794d4SMark de Wever     //
670cd794d4SMark de Wever     // The historic entries in the database are immutable. Hard-coding these
680cd794d4SMark de Wever     // values in a table would allow:
690cd794d4SMark de Wever     // - To store the sum, allowing a binary search on the data.
700cd794d4SMark de Wever     // - Avoid acquiring a mutex.
710cd794d4SMark de Wever     // The disadvantage are:
720cd794d4SMark de Wever     // - A slightly larger code size.
730cd794d4SMark de Wever     //
740cd794d4SMark de Wever     // There are two optimization directions
750cd794d4SMark de Wever     // - hard-code the database and do a linear search for future entries. This
760cd794d4SMark de Wever     //   search can start at the back, and should probably contain very few
770cd794d4SMark de Wever     //   entries. (Adding leap seconds is quite rare and new release of libc++
780cd794d4SMark de Wever     //   can add the new entries; they are announced half a year before they are
790cd794d4SMark de Wever     //   added.)
800cd794d4SMark de Wever     // - During parsing the leap seconds store an additional database in the
810cd794d4SMark de Wever     //   dylib with the list of the sum of the leap seconds. In that case there
820cd794d4SMark de Wever     //   can be a private function __get_utc_to_sys_table that returns the
830cd794d4SMark de Wever     //   table.
840cd794d4SMark de Wever     //
850cd794d4SMark de Wever     // Note for to_sys there are no optimizations to be done; it uses
860cd794d4SMark de Wever     // get_leap_second_info. The function get_leap_second_info could benefit
870cd794d4SMark de Wever     // from optimizations as described above; again both options apply.
880cd794d4SMark de Wever 
890cd794d4SMark de Wever     // Both UTC and the system clock use the same epoch. The Standard
900cd794d4SMark de Wever     // specifies from 1970-01-01 even when UTC starts at
910cd794d4SMark de Wever     // 1972-01-01 00:00:10 TAI. So when the sys_time is before epoch we can be
920cd794d4SMark de Wever     // sure there both clocks return the same value.
930cd794d4SMark de Wever 
940cd794d4SMark de Wever     const tzdb& __tzdb = chrono::get_tzdb();
950cd794d4SMark de Wever     _Rp __result{__time.time_since_epoch()};
960cd794d4SMark de Wever     for (const auto& __leap_second : __tzdb.leap_seconds) {
970cd794d4SMark de Wever       if (__leap_second > __time)
980cd794d4SMark de Wever         return __result;
990cd794d4SMark de Wever 
1000cd794d4SMark de Wever       __result += __leap_second.value();
1010cd794d4SMark de Wever     }
1020cd794d4SMark de Wever     return __result;
1030cd794d4SMark de Wever   }
1040cd794d4SMark de Wever };
1050cd794d4SMark de Wever 
1060cd794d4SMark de Wever struct leap_second_info {
1070cd794d4SMark de Wever   bool is_leap_second;
1080cd794d4SMark de Wever   seconds elapsed;
1090cd794d4SMark de Wever };
1100cd794d4SMark de Wever 
1110cd794d4SMark de Wever template <class _Duration>
1120cd794d4SMark de Wever [[nodiscard]] _LIBCPP_HIDE_FROM_ABI leap_second_info get_leap_second_info(const utc_time<_Duration>& __time) {
1130cd794d4SMark de Wever   const tzdb& __tzdb = chrono::get_tzdb();
1140cd794d4SMark de Wever   if (__tzdb.leap_seconds.empty()) [[unlikely]]
1150cd794d4SMark de Wever     return {false, chrono::seconds{0}};
1160cd794d4SMark de Wever 
1170cd794d4SMark de Wever   sys_seconds __sys{chrono::floor<seconds>(__time).time_since_epoch()};
1180cd794d4SMark de Wever   seconds __elapsed{0};
1190cd794d4SMark de Wever   for (const auto& __leap_second : __tzdb.leap_seconds) {
1200cd794d4SMark de Wever     if (__sys == __leap_second.date() + __elapsed)
1210cd794d4SMark de Wever       // A time point may only be a leap second during a positive leap second
1220cd794d4SMark de Wever       // insertion, since time points that occur during a (theoretical)
1230cd794d4SMark de Wever       // negative leap second don't exist.
1240cd794d4SMark de Wever       return {__leap_second.value() > 0s, __elapsed + __leap_second.value()};
1250cd794d4SMark de Wever 
1260cd794d4SMark de Wever     if (__sys < __leap_second.date() + __elapsed)
1270cd794d4SMark de Wever       return {false, __elapsed};
1280cd794d4SMark de Wever 
1290cd794d4SMark de Wever     __elapsed += __leap_second.value();
1300cd794d4SMark de Wever   }
1310cd794d4SMark de Wever 
1320cd794d4SMark de Wever   return {false, __elapsed};
1330cd794d4SMark de Wever }
1340cd794d4SMark de Wever 
1350cd794d4SMark de Wever template <class _Duration>
1360cd794d4SMark de Wever [[nodiscard]] _LIBCPP_HIDE_FROM_ABI sys_time<common_type_t<_Duration, seconds>>
1370cd794d4SMark de Wever utc_clock::to_sys(const utc_time<_Duration>& __time) {
1380cd794d4SMark de Wever   using _Dp               = common_type_t<_Duration, seconds>;
1390cd794d4SMark de Wever   leap_second_info __info = chrono::get_leap_second_info(__time);
1400cd794d4SMark de Wever 
1410cd794d4SMark de Wever   // [time.clock.utc.members]/2
1420cd794d4SMark de Wever   //   Returns: A sys_time t, such that from_sys(t) == u if such a mapping
1430cd794d4SMark de Wever   //   exists. Otherwise u represents a time_point during a positive leap
1440cd794d4SMark de Wever   //   second insertion, the conversion counts that leap second as not
1450cd794d4SMark de Wever   //   inserted, and the last representable value of sys_time prior to the
1460cd794d4SMark de Wever   //   insertion of the leap second is returned.
1470cd794d4SMark de Wever   sys_time<common_type_t<_Duration, seconds>> __result{__time.time_since_epoch() - __info.elapsed};
1480cd794d4SMark de Wever   if (__info.is_leap_second)
1490cd794d4SMark de Wever     return chrono::floor<seconds>(__result) + chrono::seconds{1} - _Dp{1};
1500cd794d4SMark de Wever 
1510cd794d4SMark de Wever   return __result;
1520cd794d4SMark de Wever }
1530cd794d4SMark de Wever 
1540cd794d4SMark de Wever } // namespace chrono
1550cd794d4SMark de Wever 
1560cd794d4SMark de Wever #  endif // _LIBCPP_STD_VER >= 20 && _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM &&
1570cd794d4SMark de Wever          // _LIBCPP_HAS_LOCALIZATION
1580cd794d4SMark de Wever 
1590cd794d4SMark de Wever _LIBCPP_END_NAMESPACE_STD
1600cd794d4SMark de Wever 
161*3b30f20cSMark de Wever #endif // _LIBCPP_HAS_EXPERIMENTAL_TZDB
1620cd794d4SMark de Wever 
1630cd794d4SMark de Wever #endif // _LIBCPP___CHRONO_UTC_CLOCK_H
164