Path: blob/main/contrib/llvm-project/libcxx/include/__chrono/utc_clock.h
213766 views
// -*- C++ -*-1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//89#ifndef _LIBCPP___CHRONO_UTC_CLOCK_H10#define _LIBCPP___CHRONO_UTC_CLOCK_H1112#include <version>13// Enable the contents of the header only when libc++ was built with experimental features enabled.14#if _LIBCPP_HAS_EXPERIMENTAL_TZDB1516# include <__chrono/duration.h>17# include <__chrono/leap_second.h>18# include <__chrono/system_clock.h>19# include <__chrono/time_point.h>20# include <__chrono/tzdb.h>21# include <__chrono/tzdb_list.h>22# include <__config>23# include <__type_traits/common_type.h>2425# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)26# pragma GCC system_header27# endif2829_LIBCPP_BEGIN_NAMESPACE_STD3031# if _LIBCPP_STD_VER >= 20 && _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM && _LIBCPP_HAS_LOCALIZATION3233namespace chrono {3435class utc_clock;3637template <class _Duration>38using utc_time = time_point<utc_clock, _Duration>;39using utc_seconds = utc_time<seconds>;4041class utc_clock {42public:43using rep = system_clock::rep;44using period = system_clock::period;45using duration = chrono::duration<rep, period>;46using time_point = chrono::time_point<utc_clock>;47static constexpr bool is_steady = false; // The system_clock is not steady.4849[[nodiscard]] _LIBCPP_HIDE_FROM_ABI static time_point now() { return from_sys(system_clock::now()); }5051template <class _Duration>52[[nodiscard]] _LIBCPP_HIDE_FROM_ABI static sys_time<common_type_t<_Duration, seconds>>53to_sys(const utc_time<_Duration>& __time);5455template <class _Duration>56[[nodiscard]] _LIBCPP_HIDE_FROM_ABI static utc_time<common_type_t<_Duration, seconds>>57from_sys(const sys_time<_Duration>& __time) {58using _Rp = utc_time<common_type_t<_Duration, seconds>>;59// TODO TZDB investigate optimizations.60//61// The leap second database stores all transitions, this mean to calculate62// the current number of leap seconds the code needs to iterate over all63// leap seconds to accumulate the sum. Then the sum can be used to determine64// the sys_time. Accessing the database involves acquiring a mutex.65//66// The historic entries in the database are immutable. Hard-coding these67// values in a table would allow:68// - To store the sum, allowing a binary search on the data.69// - Avoid acquiring a mutex.70// The disadvantage are:71// - A slightly larger code size.72//73// There are two optimization directions74// - hard-code the database and do a linear search for future entries. This75// search can start at the back, and should probably contain very few76// entries. (Adding leap seconds is quite rare and new release of libc++77// can add the new entries; they are announced half a year before they are78// added.)79// - During parsing the leap seconds store an additional database in the80// dylib with the list of the sum of the leap seconds. In that case there81// can be a private function __get_utc_to_sys_table that returns the82// table.83//84// Note for to_sys there are no optimizations to be done; it uses85// get_leap_second_info. The function get_leap_second_info could benefit86// from optimizations as described above; again both options apply.8788// Both UTC and the system clock use the same epoch. The Standard89// specifies from 1970-01-01 even when UTC starts at90// 1972-01-01 00:00:10 TAI. So when the sys_time is before epoch we can be91// sure there both clocks return the same value.9293const tzdb& __tzdb = chrono::get_tzdb();94_Rp __result{__time.time_since_epoch()};95for (const auto& __leap_second : __tzdb.leap_seconds) {96if (__leap_second > __time)97return __result;9899__result += __leap_second.value();100}101return __result;102}103};104105struct leap_second_info {106bool is_leap_second;107seconds elapsed;108};109110template <class _Duration>111[[nodiscard]] _LIBCPP_HIDE_FROM_ABI leap_second_info get_leap_second_info(const utc_time<_Duration>& __time) {112const tzdb& __tzdb = chrono::get_tzdb();113if (__tzdb.leap_seconds.empty()) [[unlikely]]114return {false, chrono::seconds{0}};115116sys_seconds __sys{chrono::floor<seconds>(__time).time_since_epoch()};117seconds __elapsed{0};118for (const auto& __leap_second : __tzdb.leap_seconds) {119if (__sys == __leap_second.date() + __elapsed)120// A time point may only be a leap second during a positive leap second121// insertion, since time points that occur during a (theoretical)122// negative leap second don't exist.123return {__leap_second.value() > 0s, __elapsed + __leap_second.value()};124125if (__sys < __leap_second.date() + __elapsed)126return {false, __elapsed};127128__elapsed += __leap_second.value();129}130131return {false, __elapsed};132}133134template <class _Duration>135[[nodiscard]] _LIBCPP_HIDE_FROM_ABI sys_time<common_type_t<_Duration, seconds>>136utc_clock::to_sys(const utc_time<_Duration>& __time) {137using _Dp = common_type_t<_Duration, seconds>;138leap_second_info __info = chrono::get_leap_second_info(__time);139140// [time.clock.utc.members]/2141// Returns: A sys_time t, such that from_sys(t) == u if such a mapping142// exists. Otherwise u represents a time_point during a positive leap143// second insertion, the conversion counts that leap second as not144// inserted, and the last representable value of sys_time prior to the145// insertion of the leap second is returned.146sys_time<common_type_t<_Duration, seconds>> __result{__time.time_since_epoch() - __info.elapsed};147if (__info.is_leap_second)148return chrono::floor<seconds>(__result) + chrono::seconds{1} - _Dp{1};149150return __result;151}152153} // namespace chrono154155# endif // _LIBCPP_STD_VER >= 20 && _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM &&156// _LIBCPP_HAS_LOCALIZATION157158_LIBCPP_END_NAMESPACE_STD159160#endif // _LIBCPP_HAS_EXPERIMENTAL_TZDB161162#endif // _LIBCPP___CHRONO_UTC_CLOCK_H163164165