mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-18 12:06:38 +00:00
[libc++][chrono] implements UTC clock. (#90393)
While implementing this feature and its associated LWG issues it turns out - LWG3316 Correctly define epoch for utc_clock / utc_timepoint only added non-normative wording to the standard. Implements parts of: - P0355 Extending <chrono> to Calendars and Time Zones - P1361 Integration of chrono with text formatting - LWG3359 <chrono> leap second support should allow for negative leap seconds
This commit is contained in:
parent
bd8a818128
commit
0cd794d486
@ -238,7 +238,7 @@
|
||||
"`LWG3313 <https://wg21.link/LWG3313>`__","``join_view::iterator::operator--``\ is incorrectly constrained","2020-02 (Prague)","|Complete|","14",""
|
||||
"`LWG3314 <https://wg21.link/LWG3314>`__","Is stream insertion behavior locale dependent when ``Period::type``\ is ``micro``\ ?","2020-02 (Prague)","|Complete|","16",""
|
||||
"`LWG3315 <https://wg21.link/LWG3315>`__","LWG3315: Correct Allocator Default Behavior","2020-02 (Prague)","|Complete|","",""
|
||||
"`LWG3316 <https://wg21.link/LWG3316>`__","Correctly define epoch for ``utc_clock``\ / ``utc_timepoint``\ ","2020-02 (Prague)","","",""
|
||||
"`LWG3316 <https://wg21.link/LWG3316>`__","Correctly define epoch for ``utc_clock``\ / ``utc_timepoint``\ ","2020-02 (Prague)","|Nothing To Do|","",""
|
||||
"`LWG3317 <https://wg21.link/LWG3317>`__","Incorrect ``operator<<``\ for floating-point durations","2020-02 (Prague)","|Complete|","16",""
|
||||
"`LWG3318 <https://wg21.link/LWG3318>`__","Clarify whether clocks can represent time before their epoch","2020-02 (Prague)","","",""
|
||||
"`LWG3319 <https://wg21.link/LWG3319>`__","Properly reference specification of IANA time zone database","2020-02 (Prague)","|Nothing To Do|","",""
|
||||
|
|
@ -2,7 +2,7 @@ Section,Description,Dependencies,Assignee,Status,First released version
|
||||
`P1361 <https://wg21.link/P1361>`__ `P2372 <https://wg21.link/P2372>`__,"Formatting chrono"
|
||||
`[time.syn] <https://wg21.link/time.syn>`_,"Formatter ``chrono::duration<Rep, Period>``",,Mark de Wever,|Complete|,16
|
||||
`[time.syn] <https://wg21.link/time.syn>`_,"Formatter ``chrono::sys_time<Duration>``",,Mark de Wever,|Complete|,17
|
||||
`[time.syn] <https://wg21.link/time.syn>`_,"Formatter ``chrono::utc_time<Duration>``",A ``<chrono>`` implementation,Mark de Wever,,,
|
||||
`[time.syn] <https://wg21.link/time.syn>`_,"Formatter ``chrono::utc_time<Duration>``",A ``<chrono>`` implementation,Mark de Wever,|Complete|,20
|
||||
`[time.syn] <https://wg21.link/time.syn>`_,"Formatter ``chrono::tai_time<Duration>``",A ``<chrono>`` implementation,Mark de Wever,,,
|
||||
`[time.syn] <https://wg21.link/time.syn>`_,"Formatter ``chrono::gps_time<Duration>``",A ``<chrono>`` implementation,Mark de Wever,,,
|
||||
`[time.syn] <https://wg21.link/time.syn>`_,"Formatter ``chrono::file_time<Duration>``",,Mark de Wever,|Complete|,17
|
||||
|
Can't render this file because it has a wrong number of fields in line 2.
|
@ -275,6 +275,7 @@ set(files
|
||||
__chrono/time_zone_link.h
|
||||
__chrono/tzdb.h
|
||||
__chrono/tzdb_list.h
|
||||
__chrono/utc_clock.h
|
||||
__chrono/weekday.h
|
||||
__chrono/year.h
|
||||
__chrono/year_month.h
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <__chrono/sys_info.h>
|
||||
#include <__chrono/system_clock.h>
|
||||
#include <__chrono/time_point.h>
|
||||
#include <__chrono/utc_clock.h>
|
||||
#include <__chrono/weekday.h>
|
||||
#include <__chrono/year.h>
|
||||
#include <__chrono/year_month.h>
|
||||
@ -98,6 +99,22 @@ _LIBCPP_HIDE_FROM_ABI _Tm __convert_to_tm(const chrono::sys_time<_Duration> __tp
|
||||
return __result;
|
||||
}
|
||||
|
||||
# if _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM && _LIBCPP_HAS_LOCALIZATION
|
||||
# if !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB)
|
||||
|
||||
template <class _Tm, class _Duration>
|
||||
_LIBCPP_HIDE_FROM_ABI _Tm __convert_to_tm(chrono::utc_time<_Duration> __tp) {
|
||||
_Tm __result = std::__convert_to_tm<_Tm>(chrono::utc_clock::to_sys(__tp));
|
||||
|
||||
if (chrono::get_leap_second_info(__tp).is_leap_second)
|
||||
++__result.tm_sec;
|
||||
|
||||
return __result;
|
||||
}
|
||||
|
||||
# endif // !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB)
|
||||
# endif // _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM && _LIBCPP_HAS_LOCALIZATION
|
||||
|
||||
// Convert a chrono (calendar) time point, or dururation to the given _Tm type,
|
||||
// which must have the same properties as std::tm.
|
||||
template <class _Tm, class _ChronoT>
|
||||
@ -110,6 +127,12 @@ _LIBCPP_HIDE_FROM_ABI _Tm __convert_to_tm(const _ChronoT& __value) {
|
||||
if constexpr (__is_time_point<_ChronoT>) {
|
||||
if constexpr (same_as<typename _ChronoT::clock, chrono::system_clock>)
|
||||
return std::__convert_to_tm<_Tm>(__value);
|
||||
# if _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM && _LIBCPP_HAS_LOCALIZATION
|
||||
# if !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB)
|
||||
else if constexpr (same_as<typename _ChronoT::clock, chrono::utc_clock>)
|
||||
return std::__convert_to_tm<_Tm>(__value);
|
||||
# endif // !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB)
|
||||
# endif // _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM && _LIBCPP_HAS_LOCALIZATION
|
||||
else if constexpr (same_as<typename _ChronoT::clock, chrono::file_clock>)
|
||||
return std::__convert_to_tm<_Tm>(_ChronoT::clock::to_sys(__value));
|
||||
else if constexpr (same_as<typename _ChronoT::clock, chrono::local_t>)
|
||||
|
@ -32,6 +32,7 @@
|
||||
# include <__chrono/sys_info.h>
|
||||
# include <__chrono/system_clock.h>
|
||||
# include <__chrono/time_point.h>
|
||||
# include <__chrono/utc_clock.h>
|
||||
# include <__chrono/weekday.h>
|
||||
# include <__chrono/year.h>
|
||||
# include <__chrono/year_month.h>
|
||||
@ -719,6 +720,23 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
# if _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM
|
||||
# if !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB)
|
||||
|
||||
template <class _Duration, __fmt_char_type _CharT>
|
||||
struct _LIBCPP_TEMPLATE_VIS formatter<chrono::utc_time<_Duration>, _CharT> : public __formatter_chrono<_CharT> {
|
||||
public:
|
||||
using _Base _LIBCPP_NODEBUG = __formatter_chrono<_CharT>;
|
||||
|
||||
template <class _ParseContext>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) {
|
||||
return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__clock);
|
||||
}
|
||||
};
|
||||
|
||||
# endif // !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB)
|
||||
# endif // _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM
|
||||
|
||||
template <class _Duration, __fmt_char_type _CharT>
|
||||
struct _LIBCPP_TEMPLATE_VIS formatter<chrono::file_time<_Duration>, _CharT> : public __formatter_chrono<_CharT> {
|
||||
public:
|
||||
|
@ -26,6 +26,7 @@
|
||||
# include <__chrono/statically_widen.h>
|
||||
# include <__chrono/sys_info.h>
|
||||
# include <__chrono/system_clock.h>
|
||||
# include <__chrono/utc_clock.h>
|
||||
# include <__chrono/weekday.h>
|
||||
# include <__chrono/year.h>
|
||||
# include <__chrono/year_month.h>
|
||||
@ -61,6 +62,18 @@ operator<<(basic_ostream<_CharT, _Traits>& __os, const sys_days& __dp) {
|
||||
return __os << year_month_day{__dp};
|
||||
}
|
||||
|
||||
# if _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM
|
||||
# if !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB)
|
||||
|
||||
template <class _CharT, class _Traits, class _Duration>
|
||||
_LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>&
|
||||
operator<<(basic_ostream<_CharT, _Traits>& __os, const utc_time<_Duration>& __tp) {
|
||||
return __os << std::format(__os.getloc(), _LIBCPP_STATICALLY_WIDEN(_CharT, "{:L%F %T}"), __tp);
|
||||
}
|
||||
|
||||
# endif // !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB)
|
||||
# endif // _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM
|
||||
|
||||
template <class _CharT, class _Traits, class _Duration>
|
||||
_LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>&
|
||||
operator<<(basic_ostream<_CharT, _Traits>& __os, const file_time<_Duration> __tp) {
|
||||
|
163
libcxx/include/__chrono/utc_clock.h
Normal file
163
libcxx/include/__chrono/utc_clock.h
Normal file
@ -0,0 +1,163 @@
|
||||
// -*- C++ -*-
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef _LIBCPP___CHRONO_UTC_CLOCK_H
|
||||
#define _LIBCPP___CHRONO_UTC_CLOCK_H
|
||||
|
||||
#include <version>
|
||||
// Enable the contents of the header only when libc++ was built with experimental features enabled.
|
||||
#if !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB)
|
||||
|
||||
# include <__chrono/duration.h>
|
||||
# include <__chrono/leap_second.h>
|
||||
# include <__chrono/system_clock.h>
|
||||
# include <__chrono/time_point.h>
|
||||
# include <__chrono/tzdb.h>
|
||||
# include <__chrono/tzdb_list.h>
|
||||
# include <__config>
|
||||
# include <__type_traits/common_type.h>
|
||||
|
||||
# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
# pragma GCC system_header
|
||||
# endif
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||
|
||||
# if _LIBCPP_STD_VER >= 20 && _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM && _LIBCPP_HAS_LOCALIZATION
|
||||
|
||||
namespace chrono {
|
||||
|
||||
class utc_clock;
|
||||
|
||||
template <class _Duration>
|
||||
using utc_time = time_point<utc_clock, _Duration>;
|
||||
using utc_seconds = utc_time<seconds>;
|
||||
|
||||
class utc_clock {
|
||||
public:
|
||||
using rep = system_clock::rep;
|
||||
using period = system_clock::period;
|
||||
using duration = chrono::duration<rep, period>;
|
||||
using time_point = chrono::time_point<utc_clock>;
|
||||
static constexpr bool is_steady = false; // The system_clock is not steady.
|
||||
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI static time_point now() { return from_sys(system_clock::now()); }
|
||||
|
||||
template <class _Duration>
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI static sys_time<common_type_t<_Duration, seconds>>
|
||||
to_sys(const utc_time<_Duration>& __time);
|
||||
|
||||
template <class _Duration>
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI static utc_time<common_type_t<_Duration, seconds>>
|
||||
from_sys(const sys_time<_Duration>& __time) {
|
||||
using _Rp = utc_time<common_type_t<_Duration, seconds>>;
|
||||
// TODO TZDB investigate optimizations.
|
||||
//
|
||||
// The leap second database stores all transitions, this mean to calculate
|
||||
// the current number of leap seconds the code needs to iterate over all
|
||||
// leap seconds to accumulate the sum. Then the sum can be used to determine
|
||||
// the sys_time. Accessing the database involves acquiring a mutex.
|
||||
//
|
||||
// The historic entries in the database are immutable. Hard-coding these
|
||||
// values in a table would allow:
|
||||
// - To store the sum, allowing a binary search on the data.
|
||||
// - Avoid acquiring a mutex.
|
||||
// The disadvantage are:
|
||||
// - A slightly larger code size.
|
||||
//
|
||||
// There are two optimization directions
|
||||
// - hard-code the database and do a linear search for future entries. This
|
||||
// search can start at the back, and should probably contain very few
|
||||
// entries. (Adding leap seconds is quite rare and new release of libc++
|
||||
// can add the new entries; they are announced half a year before they are
|
||||
// added.)
|
||||
// - During parsing the leap seconds store an additional database in the
|
||||
// dylib with the list of the sum of the leap seconds. In that case there
|
||||
// can be a private function __get_utc_to_sys_table that returns the
|
||||
// table.
|
||||
//
|
||||
// Note for to_sys there are no optimizations to be done; it uses
|
||||
// get_leap_second_info. The function get_leap_second_info could benefit
|
||||
// from optimizations as described above; again both options apply.
|
||||
|
||||
// Both UTC and the system clock use the same epoch. The Standard
|
||||
// specifies from 1970-01-01 even when UTC starts at
|
||||
// 1972-01-01 00:00:10 TAI. So when the sys_time is before epoch we can be
|
||||
// sure there both clocks return the same value.
|
||||
|
||||
const tzdb& __tzdb = chrono::get_tzdb();
|
||||
_Rp __result{__time.time_since_epoch()};
|
||||
for (const auto& __leap_second : __tzdb.leap_seconds) {
|
||||
if (__leap_second > __time)
|
||||
return __result;
|
||||
|
||||
__result += __leap_second.value();
|
||||
}
|
||||
return __result;
|
||||
}
|
||||
};
|
||||
|
||||
struct leap_second_info {
|
||||
bool is_leap_second;
|
||||
seconds elapsed;
|
||||
};
|
||||
|
||||
template <class _Duration>
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI leap_second_info get_leap_second_info(const utc_time<_Duration>& __time) {
|
||||
const tzdb& __tzdb = chrono::get_tzdb();
|
||||
if (__tzdb.leap_seconds.empty()) [[unlikely]]
|
||||
return {false, chrono::seconds{0}};
|
||||
|
||||
sys_seconds __sys{chrono::floor<seconds>(__time).time_since_epoch()};
|
||||
seconds __elapsed{0};
|
||||
for (const auto& __leap_second : __tzdb.leap_seconds) {
|
||||
if (__sys == __leap_second.date() + __elapsed)
|
||||
// A time point may only be a leap second during a positive leap second
|
||||
// insertion, since time points that occur during a (theoretical)
|
||||
// negative leap second don't exist.
|
||||
return {__leap_second.value() > 0s, __elapsed + __leap_second.value()};
|
||||
|
||||
if (__sys < __leap_second.date() + __elapsed)
|
||||
return {false, __elapsed};
|
||||
|
||||
__elapsed += __leap_second.value();
|
||||
}
|
||||
|
||||
return {false, __elapsed};
|
||||
}
|
||||
|
||||
template <class _Duration>
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI sys_time<common_type_t<_Duration, seconds>>
|
||||
utc_clock::to_sys(const utc_time<_Duration>& __time) {
|
||||
using _Dp = common_type_t<_Duration, seconds>;
|
||||
leap_second_info __info = chrono::get_leap_second_info(__time);
|
||||
|
||||
// [time.clock.utc.members]/2
|
||||
// Returns: A sys_time t, such that from_sys(t) == u if such a mapping
|
||||
// exists. Otherwise u represents a time_point during a positive leap
|
||||
// second insertion, the conversion counts that leap second as not
|
||||
// inserted, and the last representable value of sys_time prior to the
|
||||
// insertion of the leap second is returned.
|
||||
sys_time<common_type_t<_Duration, seconds>> __result{__time.time_since_epoch() - __info.elapsed};
|
||||
if (__info.is_leap_second)
|
||||
return chrono::floor<seconds>(__result) + chrono::seconds{1} - _Dp{1};
|
||||
|
||||
return __result;
|
||||
}
|
||||
|
||||
} // namespace chrono
|
||||
|
||||
# endif // _LIBCPP_STD_VER >= 20 && _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM &&
|
||||
// _LIBCPP_HAS_LOCALIZATION
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
#endif // !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB)
|
||||
|
||||
#endif // _LIBCPP___CHRONO_UTC_CLOCK_H
|
@ -300,6 +300,41 @@ template<class charT, class traits> // C++20
|
||||
basic_ostream<charT, traits>&
|
||||
operator<<(basic_ostream<charT, traits>& os, const sys_days& dp);
|
||||
|
||||
// [time.clock.utc], class utc_clock
|
||||
class utc_clock { // C++20
|
||||
public:
|
||||
using rep = a signed arithmetic type;
|
||||
using period = ratio<unspecified, unspecified>;
|
||||
using duration = chrono::duration<rep, period>;
|
||||
using time_point = chrono::time_point<utc_clock>;
|
||||
static constexpr bool is_steady = unspecified;
|
||||
|
||||
static time_point now();
|
||||
|
||||
template<class Duration>
|
||||
static sys_time<common_type_t<Duration, seconds>>
|
||||
to_sys(const utc_time<Duration>& t);
|
||||
template<class Duration>
|
||||
static utc_time<common_type_t<Duration, seconds>>
|
||||
from_sys(const sys_time<Duration>& t);
|
||||
};
|
||||
|
||||
template<class Duration>
|
||||
using utc_time = time_point<utc_clock, Duration>; // C++20
|
||||
using utc_seconds = utc_time<seconds>; // C++20
|
||||
|
||||
template<class charT, class traits, class Duration> // C++20
|
||||
basic_ostream<charT, traits>&
|
||||
operator<<(basic_ostream<charT, traits>& os, const utc_time<Duration>& t);
|
||||
|
||||
struct leap_second_info { // C++20
|
||||
bool is_leap_second;
|
||||
seconds elapsed;
|
||||
};
|
||||
|
||||
template<class Duration> // C++20
|
||||
leap_second_info get_leap_second_info(const utc_time<Duration>& ut);
|
||||
|
||||
class file_clock // C++20
|
||||
{
|
||||
public:
|
||||
@ -861,6 +896,8 @@ strong_ordering operator<=>(const time_zone_link& x, const time_zone_link& y);
|
||||
namespace std {
|
||||
template<class Duration, class charT>
|
||||
struct formatter<chrono::sys_time<Duration>, charT>; // C++20
|
||||
template<class Duration, class charT>
|
||||
struct formatter<chrono::utc_time<Duration>, charT>; // C++20
|
||||
template<class Duration, class charT>
|
||||
struct formatter<chrono::filetime<Duration>, charT>; // C++20
|
||||
template<class Duration, class charT>
|
||||
@ -981,6 +1018,7 @@ constexpr chrono::year operator ""y(unsigned lo
|
||||
# include <__chrono/time_zone_link.h>
|
||||
# include <__chrono/tzdb.h>
|
||||
# include <__chrono/tzdb_list.h>
|
||||
# include <__chrono/utc_clock.h>
|
||||
# include <__chrono/zoned_time.h>
|
||||
# endif
|
||||
|
||||
|
@ -980,6 +980,10 @@ module std [system] {
|
||||
export std.string // public data member of type std::string
|
||||
export std.vector // public data members of type std::vector
|
||||
}
|
||||
module utc_clock {
|
||||
header "__chrono/utc_clock.h"
|
||||
export std.chrono.time_point
|
||||
}
|
||||
module weekday { header "__chrono/weekday.h" }
|
||||
module year_month_day { header "__chrono/year_month_day.h" }
|
||||
module year_month_weekday { header "__chrono/year_month_weekday.h" }
|
||||
|
@ -84,7 +84,9 @@ export namespace std {
|
||||
using std::chrono::sys_seconds;
|
||||
using std::chrono::sys_time;
|
||||
|
||||
#if 0
|
||||
#if _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM && _LIBCPP_HAS_LOCALIZATION
|
||||
# ifdef _LIBCPP_ENABLE_EXPERIMENTAL
|
||||
|
||||
// [time.clock.utc], class utc_clock
|
||||
using std::chrono::utc_clock;
|
||||
|
||||
@ -94,6 +96,8 @@ export namespace std {
|
||||
using std::chrono::leap_second_info;
|
||||
|
||||
using std::chrono::get_leap_second_info;
|
||||
|
||||
# if 0
|
||||
// [time.clock.tai], class tai_clock
|
||||
using std::chrono::tai_clock;
|
||||
|
||||
@ -105,7 +109,10 @@ export namespace std {
|
||||
|
||||
using std::chrono::gps_seconds;
|
||||
using std::chrono::gps_time;
|
||||
#endif
|
||||
# endif
|
||||
# endif // _LIBCPP_ENABLE_EXPERIMENTAL
|
||||
#endif // _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM && _LIBCPP_HAS_LOCALIZATION
|
||||
|
||||
// [time.clock.file], type file_clock
|
||||
using std::chrono::file_clock;
|
||||
|
||||
|
60
libcxx/test/benchmarks/utc_clock.bench.cpp
Normal file
60
libcxx/test/benchmarks/utc_clock.bench.cpp
Normal file
@ -0,0 +1,60 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: no-filesystem, no-localization, no-tzdb
|
||||
|
||||
// XFAIL: libcpp-has-no-experimental-tzdb
|
||||
// XFAIL: availability-tzdb-missing
|
||||
|
||||
#include <chrono>
|
||||
|
||||
#include "benchmark/benchmark.h"
|
||||
|
||||
// Benchmarks the performance of the UTC <-> system time conversions. These
|
||||
// operations determine the sum of leap second insertions at a specific time.
|
||||
|
||||
static void BM_from_sys(benchmark::State& state) {
|
||||
std::chrono::sys_days date{std::chrono::July / 1 / state.range(0)};
|
||||
for (auto _ : state)
|
||||
benchmark::DoNotOptimize(std::chrono::utc_clock::from_sys(date));
|
||||
}
|
||||
|
||||
BENCHMARK(BM_from_sys)
|
||||
->Arg(1970) // before the first leap seconds
|
||||
->Arg(1979) // in the first half of inserted leap seconds
|
||||
->Arg(1993) // in the second half of inserted leap seconds
|
||||
->Arg(2100); // after the last leap second
|
||||
|
||||
BENCHMARK(BM_from_sys)->Arg(1970)->Arg(1979)->Arg(1993)->Arg(2100)->Threads(4);
|
||||
BENCHMARK(BM_from_sys)->Arg(1970)->Arg(1979)->Arg(1993)->Arg(2100)->Threads(16);
|
||||
|
||||
static void BM_to_sys(benchmark::State& state) {
|
||||
// 59 sec offset means we pass th UTC offset for the leap second; assuming
|
||||
// there won't be more than 59 leap seconds ever.
|
||||
std::chrono::utc_seconds date{
|
||||
std::chrono::sys_days{std::chrono::July / 1 / state.range(0)}.time_since_epoch() + std::chrono::seconds{59}};
|
||||
for (auto _ : state)
|
||||
benchmark::DoNotOptimize(std::chrono::utc_clock::to_sys(date));
|
||||
}
|
||||
|
||||
BENCHMARK(BM_to_sys)
|
||||
->Arg(1970) // before the first leap seconds
|
||||
->Arg(1979) // in the first half of inserted leap seconds
|
||||
->Arg(1993) // in the second half of inserted leap seconds
|
||||
->Arg(2100); // after the last leap second
|
||||
|
||||
BENCHMARK(BM_to_sys)->Arg(1970)->Arg(1979)->Arg(1993)->Arg(2100)->Threads(4);
|
||||
BENCHMARK(BM_to_sys)->Arg(1970)->Arg(1979)->Arg(1993)->Arg(2100)->Threads(16);
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
benchmark::Initialize(&argc, argv);
|
||||
if (benchmark::ReportUnrecognizedArguments(argc, argv))
|
||||
return 1;
|
||||
|
||||
benchmark::RunSpecifiedBenchmarks();
|
||||
}
|
@ -75,6 +75,20 @@ void test(std::chrono::time_zone tz, std::chrono::time_zone_link link, std::chro
|
||||
t::locate_zone(""); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
}
|
||||
|
||||
{ // [time.clock.utc]
|
||||
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
std::chrono::utc_clock::now();
|
||||
|
||||
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
std::chrono::utc_clock::to_sys(std::chrono::utc_seconds{});
|
||||
|
||||
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
std::chrono::utc_clock::from_sys(std::chrono::sys_seconds{});
|
||||
|
||||
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
|
||||
std::chrono::get_leap_second_info(std::chrono::utc_seconds{});
|
||||
}
|
||||
|
||||
{
|
||||
std::chrono::zoned_time<std::chrono::seconds> zt;
|
||||
|
||||
|
@ -0,0 +1,147 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: no-filesystem, no-localization, no-tzdb
|
||||
|
||||
// XFAIL: libcpp-has-no-experimental-tzdb
|
||||
// XFAIL: availability-tzdb-missing
|
||||
|
||||
// <chrono>
|
||||
//
|
||||
// class utc_clock;
|
||||
|
||||
// template<class Duration>
|
||||
// std::chrono::leap_second_info get_leap_second_info(const utc_time<Duration>& ut);
|
||||
|
||||
#include <chrono>
|
||||
#include <cassert>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "assert_macros.h"
|
||||
#include "concat_macros.h"
|
||||
#include "filesystem_test_helper.h"
|
||||
#include "test_tzdb.h"
|
||||
|
||||
scoped_test_env env;
|
||||
[[maybe_unused]] const std::filesystem::path dir = env.create_dir("zoneinfo");
|
||||
const std::filesystem::path tzdata = env.create_file("zoneinfo/tzdata.zi");
|
||||
const std::filesystem::path leap_seconds = env.create_file("zoneinfo/leap-seconds.list");
|
||||
|
||||
std::string_view std::chrono::__libcpp_tzdb_directory() {
|
||||
static std::string result = dir.string();
|
||||
return result;
|
||||
}
|
||||
|
||||
static void write(std::string_view input) {
|
||||
static int version = 0;
|
||||
|
||||
{
|
||||
std::ofstream f{tzdata};
|
||||
f << "# version " << version++ << '\n';
|
||||
std::ofstream{leap_seconds}.write(input.data(), input.size());
|
||||
}
|
||||
std::chrono::reload_tzdb();
|
||||
}
|
||||
|
||||
template <class Duration>
|
||||
static void test_leap_second_info(
|
||||
std::chrono::time_point<std::chrono::utc_clock, Duration> time, bool is_leap_second, std::chrono::seconds elapsed) {
|
||||
std::chrono::leap_second_info result = std::chrono::get_leap_second_info(time);
|
||||
TEST_REQUIRE(
|
||||
result.is_leap_second == is_leap_second && result.elapsed == elapsed,
|
||||
TEST_WRITE_CONCATENATED(
|
||||
"\nExpected output [",
|
||||
is_leap_second,
|
||||
", ",
|
||||
elapsed,
|
||||
"]\nActual output [",
|
||||
result.is_leap_second,
|
||||
", ",
|
||||
result.elapsed,
|
||||
"]\n"));
|
||||
}
|
||||
|
||||
static void test_no_leap_seconds_entries() {
|
||||
using namespace std::literals::chrono_literals;
|
||||
|
||||
write("");
|
||||
|
||||
test_leap_second_info(
|
||||
std::chrono::utc_seconds{std::chrono::sys_days{std::chrono::January / 1 / 1900}.time_since_epoch()}, false, 0s);
|
||||
test_leap_second_info(
|
||||
std::chrono::utc_seconds{std::chrono::sys_days{std::chrono::January / 1 / 2000}.time_since_epoch()}, false, 0s);
|
||||
test_leap_second_info(
|
||||
std::chrono::utc_seconds{std::chrono::sys_days{std::chrono::January / 1 / 3000}.time_since_epoch()}, false, 0s);
|
||||
}
|
||||
|
||||
// Note at the time of writing all leap seconds are positive. This test uses
|
||||
// fake data to test the behaviour of negative leap seconds.
|
||||
static void test_negative_leap_seconds() {
|
||||
using namespace std::literals::chrono_literals;
|
||||
|
||||
// Use small values for simplicity. The dates are seconds since 1.1.1900.
|
||||
write(
|
||||
R"(
|
||||
1 10
|
||||
60 11
|
||||
120 12
|
||||
180 11
|
||||
240 12
|
||||
300 13
|
||||
360 12
|
||||
)");
|
||||
|
||||
// Transitions from the start of UTC.
|
||||
auto test_transition = [](std::chrono::utc_seconds time, std::chrono::seconds elapsed, bool positive) {
|
||||
if (positive) {
|
||||
// Every transition has the following tests
|
||||
// - 1ns before the start of the transition is_leap_second -> false, elapsed -> elapsed
|
||||
// - at the start of the transition is_leap_second -> true, elapsed -> elapsed + 1
|
||||
// - 1ns after the start of the transition is_leap_second -> true, elapsed -> elapsed + 1
|
||||
// - 1ns before the end of the transition is_leap_second -> true, elapsed -> elapsed + 1
|
||||
// - at the end of the transition is_leap_second -> false, elapsed -> elapsed + 1
|
||||
|
||||
test_leap_second_info(time - 1ns, false, elapsed);
|
||||
test_leap_second_info(time, true, elapsed + 1s);
|
||||
test_leap_second_info(time + 1ns, true, elapsed + 1s);
|
||||
test_leap_second_info(time + 1s - 1ns, true, elapsed + 1s);
|
||||
test_leap_second_info(time + 1s, false, elapsed + 1s);
|
||||
} else {
|
||||
// Every transition has the following tests
|
||||
// - 1ns before the transition is_leap_second -> false, elapsed -> elapsed
|
||||
// - at the transition is_leap_second -> false elapsed -> elapsed - 1
|
||||
// - 1ns after the transition is_leap_second -> false, elapsed -> elapsed - 1
|
||||
test_leap_second_info(time - 1ns, false, elapsed);
|
||||
test_leap_second_info(time, false, elapsed - 1s);
|
||||
test_leap_second_info(time + 1ns, false, elapsed - 1s);
|
||||
}
|
||||
};
|
||||
|
||||
std::chrono::utc_seconds epoch{std::chrono::sys_days{std::chrono::January / 1 / 1900}.time_since_epoch()};
|
||||
test_leap_second_info(epoch, false, 0s);
|
||||
|
||||
// The UTC times are:
|
||||
// epoch + transition time in the database + leap seconds before the transition.
|
||||
test_transition(epoch + 60s + 0s, 0s, true);
|
||||
test_transition(epoch + 120s + 1s, 1s, true);
|
||||
test_transition(epoch + 180s + 2s, 2s, false);
|
||||
test_transition(epoch + 240s + 1s, 1s, true);
|
||||
test_transition(epoch + 300s + 2s, 2s, true);
|
||||
test_transition(epoch + 360s + 3s, 3s, false);
|
||||
}
|
||||
|
||||
int main(int, const char**) {
|
||||
test_no_leap_seconds_entries();
|
||||
test_negative_leap_seconds();
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,108 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: no-filesystem, no-localization, no-tzdb
|
||||
|
||||
// XFAIL: libcpp-has-no-experimental-tzdb
|
||||
// XFAIL: availability-tzdb-missing
|
||||
|
||||
// <chrono>
|
||||
//
|
||||
// class utc_clock;
|
||||
|
||||
// template<class Duration>
|
||||
// static utc_time<common_type_t<Duration, seconds>>
|
||||
// from_sys(const sys_time<Duration>& time);
|
||||
|
||||
#include <chrono>
|
||||
#include <cassert>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "assert_macros.h"
|
||||
#include "concat_macros.h"
|
||||
#include "filesystem_test_helper.h"
|
||||
#include "test_tzdb.h"
|
||||
|
||||
scoped_test_env env;
|
||||
[[maybe_unused]] const std::filesystem::path dir = env.create_dir("zoneinfo");
|
||||
const std::filesystem::path tzdata = env.create_file("zoneinfo/tzdata.zi");
|
||||
const std::filesystem::path leap_seconds = env.create_file("zoneinfo/leap-seconds.list");
|
||||
|
||||
std::string_view std::chrono::__libcpp_tzdb_directory() {
|
||||
static std::string result = dir.string();
|
||||
return result;
|
||||
}
|
||||
|
||||
static void write(std::string_view input) {
|
||||
static int version = 0;
|
||||
|
||||
std::ofstream f{tzdata};
|
||||
f << "# version " << version++ << '\n';
|
||||
std::ofstream{leap_seconds}.write(input.data(), input.size());
|
||||
}
|
||||
|
||||
template <class Duration>
|
||||
static void
|
||||
test_leap_seconds(std::chrono::time_point<std::chrono::system_clock, Duration> time, std::chrono::seconds expected) {
|
||||
auto utc = std::chrono::utc_clock::from_sys(time);
|
||||
auto diff = utc.time_since_epoch() - time.time_since_epoch();
|
||||
TEST_REQUIRE(
|
||||
diff == expected,
|
||||
TEST_WRITE_CONCATENATED("\tTime: ", time, "\nExpected output ", expected, "\nActual output ", diff, '\n'));
|
||||
}
|
||||
|
||||
// Note at the time of writing all leap seconds are positive. This test uses
|
||||
// fake data to test the behaviour of negative leap seconds.
|
||||
int main(int, const char**) {
|
||||
using namespace std::literals::chrono_literals;
|
||||
|
||||
// Use small values for simplicity. The dates are seconds since 1.1.1970.
|
||||
write(
|
||||
R"(
|
||||
1 10
|
||||
60 11
|
||||
120 12
|
||||
180 11
|
||||
240 12
|
||||
300 13
|
||||
360 12
|
||||
)");
|
||||
|
||||
std::chrono::sys_days epoch = {std::chrono::January / 1 / 1900};
|
||||
test_leap_seconds(epoch, 0s);
|
||||
|
||||
test_leap_seconds(epoch + 60s - 1ns, 0s);
|
||||
test_leap_seconds(epoch + 60s, 1s);
|
||||
test_leap_seconds(epoch + 60s + 1ns, 1s);
|
||||
|
||||
test_leap_seconds(epoch + 120s - 1ns, 1s);
|
||||
test_leap_seconds(epoch + 120s, 2s);
|
||||
test_leap_seconds(epoch + 120s + 1ns, 2s);
|
||||
|
||||
test_leap_seconds(epoch + 180s - 1ns, 2s);
|
||||
test_leap_seconds(epoch + 180s, 1s);
|
||||
test_leap_seconds(epoch + 180s + 1ns, 1s);
|
||||
|
||||
test_leap_seconds(epoch + 240s - 1ns, 1s);
|
||||
test_leap_seconds(epoch + 240s, 2s);
|
||||
test_leap_seconds(epoch + 240s + 1ns, 2s);
|
||||
|
||||
test_leap_seconds(epoch + 300s - 1ns, 2s);
|
||||
test_leap_seconds(epoch + 300s, 3s);
|
||||
test_leap_seconds(epoch + 300s + 1ns, 3s);
|
||||
|
||||
test_leap_seconds(epoch + 360s - 1ns, 3s);
|
||||
test_leap_seconds(epoch + 360s, 2s);
|
||||
test_leap_seconds(epoch + 360s + 1ns, 2s);
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,117 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: no-filesystem, no-localization, no-tzdb
|
||||
|
||||
// XFAIL: libcpp-has-no-experimental-tzdb
|
||||
// XFAIL: availability-tzdb-missing
|
||||
|
||||
// <chrono>
|
||||
//
|
||||
// class utc_clock;
|
||||
|
||||
// static sys_time<common_type_t<_Duration, seconds>>
|
||||
// to_sys(const utc_time<_Duration>& __time);
|
||||
|
||||
#include <chrono>
|
||||
#include <cassert>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "assert_macros.h"
|
||||
#include "concat_macros.h"
|
||||
#include "filesystem_test_helper.h"
|
||||
#include "test_tzdb.h"
|
||||
|
||||
scoped_test_env env;
|
||||
[[maybe_unused]] const std::filesystem::path dir = env.create_dir("zoneinfo");
|
||||
const std::filesystem::path tzdata = env.create_file("zoneinfo/tzdata.zi");
|
||||
const std::filesystem::path leap_seconds = env.create_file("zoneinfo/leap-seconds.list");
|
||||
|
||||
std::string_view std::chrono::__libcpp_tzdb_directory() {
|
||||
static std::string result = dir.string();
|
||||
return result;
|
||||
}
|
||||
|
||||
static void write(std::string_view input) {
|
||||
static int version = 0;
|
||||
|
||||
std::ofstream f{tzdata};
|
||||
f << "# version " << version++ << '\n';
|
||||
std::ofstream{leap_seconds}.write(input.data(), input.size());
|
||||
}
|
||||
|
||||
template <class Duration>
|
||||
static void test_leap_seconds(std::chrono::utc_time<Duration> time, std::chrono::sys_time<Duration> expected) {
|
||||
auto result = std::chrono::utc_clock::to_sys(time);
|
||||
TEST_REQUIRE(result == expected,
|
||||
TEST_WRITE_CONCATENATED("\nExpected output ", expected, "\nActual output ", result, '\n'));
|
||||
}
|
||||
|
||||
// Note at the time of writing all leap seconds are positive. This test uses
|
||||
// fake data to test the behaviour of negative leap seconds.
|
||||
int main(int, const char**) {
|
||||
using namespace std::literals::chrono_literals;
|
||||
|
||||
// Use small values for simplicity. The dates are seconds since 1.1.1970.
|
||||
write(
|
||||
R"(
|
||||
1 10
|
||||
60 11
|
||||
120 12
|
||||
180 11
|
||||
240 12
|
||||
300 13
|
||||
360 12
|
||||
)");
|
||||
|
||||
std::chrono::sys_seconds sys_epoch{std::chrono::sys_days{std::chrono::January / 1 / 1900}};
|
||||
std::chrono::utc_seconds utc_epoch{sys_epoch.time_since_epoch()};
|
||||
|
||||
test_leap_seconds(utc_epoch, sys_epoch);
|
||||
auto test_transition = [](std::chrono::sys_seconds sys, std::chrono::seconds elapsed, bool positive) {
|
||||
std::chrono::utc_seconds utc = std::chrono::utc_seconds{sys.time_since_epoch()} + elapsed;
|
||||
if (positive) {
|
||||
// Every transition has the following tests
|
||||
// - 1ns before the start of the transition no adjustment needed
|
||||
// - at the start of the transition sys is clamped at the time just prior to the moment
|
||||
// of the leap second insertion. The exact value depends
|
||||
// on the resolution of the result type.
|
||||
// - 1ns before the end of the transition sys is still clamped like before
|
||||
// - at the end of the transition sys is 1s behind the utc time
|
||||
// - 1ns after the end of the transition sys is still 1s behind the utc time
|
||||
test_leap_seconds(utc - 1ns, sys - 1ns);
|
||||
test_leap_seconds(utc, sys - 1s);
|
||||
test_leap_seconds(utc + 0ns, sys - 1ns);
|
||||
test_leap_seconds(utc + 1s - 1ns, sys - 1ns);
|
||||
test_leap_seconds(utc + 1s, sys);
|
||||
test_leap_seconds(utc + 1s + 0ns, sys + 0ns);
|
||||
test_leap_seconds(utc + 1s + 1ns, sys + 1ns);
|
||||
} else {
|
||||
// Every transition has the following tests
|
||||
// - 1ns before the transition no adjustment needed
|
||||
// - at the transition sys is 1s ahead of the utc time
|
||||
// - 1ns after the transition sys is still 1s ahead of the utc time
|
||||
test_leap_seconds(utc - 1ns, sys - 1ns);
|
||||
test_leap_seconds(utc, sys + 1s);
|
||||
test_leap_seconds(utc + 1ns, sys + 1s + 1ns);
|
||||
}
|
||||
};
|
||||
|
||||
test_transition(sys_epoch + 60s, 0s, true);
|
||||
test_transition(sys_epoch + 120s, 1s, true);
|
||||
test_transition(sys_epoch + 180s, 2s, false);
|
||||
test_transition(sys_epoch + 240s, 1s, true);
|
||||
test_transition(sys_epoch + 300s, 2s, true);
|
||||
test_transition(sys_epoch + 360s, 3s, false);
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,128 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: no-filesystem, no-localization, no-tzdb
|
||||
|
||||
// XFAIL: libcpp-has-no-experimental-tzdb
|
||||
// XFAIL: availability-tzdb-missing
|
||||
|
||||
// <chrono>
|
||||
//
|
||||
// class utc_clock;
|
||||
|
||||
// template<class Duration>
|
||||
// leap_second_info get_leap_second_info(const utc_time<Duration>& ut);
|
||||
|
||||
#include <chrono>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "assert_macros.h"
|
||||
#include "concat_macros.h"
|
||||
|
||||
template <class Duration>
|
||||
static void test_leap_second_info(
|
||||
std::chrono::time_point<std::chrono::utc_clock, Duration> time, bool is_leap_second, std::chrono::seconds elapsed) {
|
||||
std::chrono::leap_second_info result = std::chrono::get_leap_second_info(time);
|
||||
TEST_REQUIRE(
|
||||
result.is_leap_second == is_leap_second && result.elapsed == elapsed,
|
||||
TEST_WRITE_CONCATENATED(
|
||||
"\nExpected output [",
|
||||
is_leap_second,
|
||||
", ",
|
||||
elapsed,
|
||||
"]\nActual output [",
|
||||
result.is_leap_second,
|
||||
", ",
|
||||
result.elapsed,
|
||||
"]\n"));
|
||||
}
|
||||
|
||||
static std::chrono::utc_seconds get_utc_time(long long seconds_since_1900) {
|
||||
// The file leap-seconds.list stores dates since 1 January 1900, 00:00:00, we want
|
||||
// seconds since 1 January 1970.
|
||||
constexpr auto offset =
|
||||
std::chrono::sys_days{std::chrono::January / 1 / 1970} - std::chrono::sys_days{std::chrono::January / 1 / 1900};
|
||||
return std::chrono::utc_seconds{std::chrono::seconds{seconds_since_1900} - offset};
|
||||
}
|
||||
|
||||
// Tests set of existing database entries at the time of writing.
|
||||
int main(int, const char**) {
|
||||
using namespace std::literals::chrono_literals;
|
||||
|
||||
test_leap_second_info(std::chrono::utc_seconds::min(), false, 0s);
|
||||
|
||||
// Epoch transition no transitions.
|
||||
test_leap_second_info(std::chrono::utc_seconds{-1s}, false, 0s);
|
||||
test_leap_second_info(std::chrono::utc_seconds{0s}, false, 0s);
|
||||
test_leap_second_info(std::chrono::utc_seconds{1s}, false, 0s);
|
||||
|
||||
// Transitions from the start of UTC.
|
||||
auto test_transition = [](std::chrono::utc_seconds time, std::chrono::seconds elapsed, bool positive) {
|
||||
// Note at the time of writing all leap seconds are positive so the else
|
||||
// branch is never executed. The private test for this function tests
|
||||
// negative leap seconds and uses the else branch.
|
||||
|
||||
if (positive) {
|
||||
// Every transition has the following tests
|
||||
// - 1ns before the start of the transition is_leap_second -> false, elapsed -> elapsed
|
||||
// - at the start of the transition is_leap_second -> true, elapsed -> elapsed + 1
|
||||
// - 1ns after the start of the transition is_leap_second -> true, elapsed -> elapsed + 1
|
||||
// - 1ns before the end of the transition is_leap_second -> true, elapsed -> elapsed + 1
|
||||
// - at the end of the transition is_leap_second -> false, elapsed -> elapsed + 1
|
||||
|
||||
test_leap_second_info(time - 1ns, false, elapsed);
|
||||
test_leap_second_info(time, true, elapsed + 1s);
|
||||
test_leap_second_info(time + 1ns, true, elapsed + 1s);
|
||||
test_leap_second_info(time + 1s - 1ns, true, elapsed + 1s);
|
||||
test_leap_second_info(time + 1s, false, elapsed + 1s);
|
||||
} else {
|
||||
// Every transition has the following tests
|
||||
// - 1ns before the transition is_leap_second -> false, elapsed -> elapsed
|
||||
// - at the transition is_leap_second -> false elapsed -> elapsed - 1
|
||||
// - 1ns after the transition is_leap_second -> false, elapsed -> elapsed - 1
|
||||
test_leap_second_info(time - 1ns, false, elapsed);
|
||||
test_leap_second_info(time, false, elapsed - 1s);
|
||||
test_leap_second_info(time + 1ns, false, elapsed - 1s);
|
||||
}
|
||||
};
|
||||
|
||||
// The timestamps are from leap-seconds.list in the IANA database.
|
||||
// Note the times stamps are timestamps without leap seconds so the number
|
||||
// here are incremented by x "leap seconds".
|
||||
test_transition(get_utc_time(2287785600 + 0), 0s, true); // 1 Jul 1972
|
||||
test_transition(get_utc_time(2303683200 + 1), 1s, true); // 1 Jan 1973
|
||||
test_transition(get_utc_time(2335219200 + 2), 2s, true); // 1 Jan 1974
|
||||
test_transition(get_utc_time(2366755200 + 3), 3s, true); // 1 Jan 1975
|
||||
test_transition(get_utc_time(2398291200 + 4), 4s, true); // 1 Jan 1976
|
||||
test_transition(get_utc_time(2429913600 + 5), 5s, true); // 1 Jan 1977
|
||||
test_transition(get_utc_time(2461449600 + 6), 6s, true); // 1 Jan 1978
|
||||
test_transition(get_utc_time(2492985600 + 7), 7s, true); // 1 Jan 1979
|
||||
test_transition(get_utc_time(2524521600 + 8), 8s, true); // 1 Jan 1980
|
||||
test_transition(get_utc_time(2571782400 + 9), 9s, true); // 1 Jul 1981
|
||||
test_transition(get_utc_time(2603318400 + 10), 10s, true); // 1 Jul 1982
|
||||
test_transition(get_utc_time(2634854400 + 11), 11s, true); // 1 Jul 1983
|
||||
test_transition(get_utc_time(2698012800 + 12), 12s, true); // 1 Jul 1985
|
||||
test_transition(get_utc_time(2776982400 + 13), 13s, true); // 1 Jan 1988
|
||||
test_transition(get_utc_time(2840140800 + 14), 14s, true); // 1 Jan 1990
|
||||
test_transition(get_utc_time(2871676800 + 15), 15s, true); // 1 Jan 1991
|
||||
test_transition(get_utc_time(2918937600 + 16), 16s, true); // 1 Jul 1992
|
||||
test_transition(get_utc_time(2950473600 + 17), 17s, true); // 1 Jul 1993
|
||||
test_transition(get_utc_time(2982009600 + 18), 18s, true); // 1 Jul 1994
|
||||
test_transition(get_utc_time(3029443200 + 19), 19s, true); // 1 Jan 1996
|
||||
test_transition(get_utc_time(3076704000 + 20), 20s, true); // 1 Jul 1997
|
||||
test_transition(get_utc_time(3124137600 + 21), 21s, true); // 1 Jan 1999
|
||||
test_transition(get_utc_time(3345062400 + 22), 22s, true); // 1 Jan 2006
|
||||
test_transition(get_utc_time(3439756800 + 23), 23s, true); // 1 Jan 2009
|
||||
test_transition(get_utc_time(3550089600 + 24), 24s, true); // 1 Jul 2012
|
||||
test_transition(get_utc_time(3644697600 + 25), 25s, true); // 1 Jul 2015
|
||||
test_transition(get_utc_time(3692217600 + 26), 26s, true); // 1 Jan 2017
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: no-filesystem, no-localization, no-tzdb
|
||||
|
||||
// XFAIL: libcpp-has-no-experimental-tzdb
|
||||
// XFAIL: availability-tzdb-missing
|
||||
|
||||
// <chrono>
|
||||
|
||||
// struct leap_second_info {
|
||||
// bool is_leap_second;
|
||||
// seconds elapsed;
|
||||
// };
|
||||
|
||||
#include <chrono>
|
||||
#include <type_traits>
|
||||
|
||||
// Validates whether:
|
||||
// - The members are present as non-const members.
|
||||
// - The struct is an aggregate.
|
||||
int main(int, const char**) {
|
||||
static_assert(std::is_aggregate_v<std::chrono::leap_second_info>);
|
||||
|
||||
std::chrono::leap_second_info leap_second_info{.is_leap_second = false, .elapsed = std::chrono::seconds(0)};
|
||||
|
||||
[[maybe_unused]] bool& is_leap_second = leap_second_info.is_leap_second;
|
||||
[[maybe_unused]] std::chrono::seconds& elapsed = leap_second_info.elapsed;
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,245 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: no-filesystem, no-localization, no-tzdb
|
||||
|
||||
// XFAIL: libcpp-has-no-experimental-tzdb
|
||||
// XFAIL: availability-tzdb-missing
|
||||
|
||||
// <chrono>
|
||||
//
|
||||
// class utc_clock;
|
||||
|
||||
// template<class Duration>
|
||||
// static utc_time<common_type_t<Duration, seconds>>
|
||||
// from_sys(const sys_time<Duration>& time);
|
||||
|
||||
#include <chrono>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "assert_macros.h"
|
||||
#include "concat_macros.h"
|
||||
|
||||
template <class Duration>
|
||||
static void test_leap_seconds(std::chrono::time_point<std::chrono::system_clock, Duration> time,
|
||||
std::chrono::seconds leap_seconds) {
|
||||
auto utc = std::chrono::utc_clock::from_sys(time);
|
||||
auto diff = utc.time_since_epoch() - time.time_since_epoch();
|
||||
TEST_REQUIRE(
|
||||
diff == leap_seconds,
|
||||
TEST_WRITE_CONCATENATED("\tTime: ", time, "\nExpected output ", leap_seconds, "\nActual output ", diff, '\n'));
|
||||
}
|
||||
|
||||
// This test is based on the example in [time.clock.utc.members]/3
|
||||
static void test_example_standard() {
|
||||
using namespace std::literals::chrono_literals;
|
||||
|
||||
auto t = std::chrono::sys_days{std::chrono::July / 1 / 2015} - 2ns;
|
||||
test_leap_seconds(t, 25s);
|
||||
|
||||
t += 1ns;
|
||||
test_leap_seconds(t, 25s);
|
||||
|
||||
t += 1ns;
|
||||
test_leap_seconds(t, 26s);
|
||||
|
||||
t += 1ns;
|
||||
test_leap_seconds(t, 26s);
|
||||
}
|
||||
|
||||
// Tests set of existing database entries at the time of writing.
|
||||
static void test_transitions() {
|
||||
using namespace std::literals::chrono_literals;
|
||||
|
||||
test_leap_seconds(std::chrono::sys_seconds::min(), 0s);
|
||||
test_leap_seconds(std::chrono::sys_days::min(), 0s);
|
||||
|
||||
// Epoch transition no transitions.
|
||||
test_leap_seconds(std::chrono::sys_seconds{-1s}, 0s);
|
||||
test_leap_seconds(std::chrono::sys_seconds{0s}, 0s);
|
||||
test_leap_seconds(std::chrono::sys_seconds{1s}, 0s);
|
||||
|
||||
// Transitions from the start of UTC.
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::January / 1 / 1972} - 1ns, 0s);
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::January / 1 / 1972}, 0s);
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::January / 1 / 1972} + 1ns, 0s);
|
||||
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::July / 1 / 1972} - 1ns, 0s);
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::July / 1 / 1972}, 1s);
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::July / 1 / 1972} + 1ns, 1s);
|
||||
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::January / 1 / 1973} - 1ns, 1s);
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::January / 1 / 1973}, 2s);
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::January / 1 / 1973} + 1ns, 2s);
|
||||
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::January / 1 / 1974} - 1ns, 2s);
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::January / 1 / 1974}, 3s);
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::January / 1 / 1974} + 1ns, 3s);
|
||||
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::January / 1 / 1975} - 1ns, 3s);
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::January / 1 / 1975}, 4s);
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::January / 1 / 1975} + 1ns, 4s);
|
||||
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::January / 1 / 1976} - 1ns, 4s);
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::January / 1 / 1976}, 5s);
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::January / 1 / 1976} + 1ns, 5s);
|
||||
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::January / 1 / 1977} - 1ns, 5s);
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::January / 1 / 1977}, 6s);
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::January / 1 / 1977} + 1ns, 6s);
|
||||
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::January / 1 / 1978} - 1ns, 6s);
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::January / 1 / 1978}, 7s);
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::January / 1 / 1978} + 1ns, 7s);
|
||||
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::January / 1 / 1979} - 1ns, 7s);
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::January / 1 / 1979}, 8s);
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::January / 1 / 1979} + 1ns, 8s);
|
||||
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::January / 1 / 1980} - 1ns, 8s);
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::January / 1 / 1980}, 9s);
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::January / 1 / 1980} + 1ns, 9s);
|
||||
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::July / 1 / 1981} - 1ns, 9s);
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::July / 1 / 1981}, 10s);
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::July / 1 / 1981} + 1ns, 10s);
|
||||
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::July / 1 / 1982} - 1ns, 10s);
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::July / 1 / 1982}, 11s);
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::July / 1 / 1982} + 1ns, 11s);
|
||||
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::July / 1 / 1983} - 1ns, 11s);
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::July / 1 / 1983}, 12s);
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::July / 1 / 1983} + 1ns, 12s);
|
||||
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::July / 1 / 1985} - 1ns, 12s);
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::July / 1 / 1985}, 13s);
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::July / 1 / 1985} + 1ns, 13s);
|
||||
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::January / 1 / 1988} - 1ns, 13s);
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::January / 1 / 1988}, 14s);
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::January / 1 / 1988} + 1ns, 14s);
|
||||
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::January / 1 / 1990} - 1ns, 14s);
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::January / 1 / 1990}, 15s);
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::January / 1 / 1990} + 1ns, 15s);
|
||||
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::January / 1 / 1991} - 1ns, 15s);
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::January / 1 / 1991}, 16s);
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::January / 1 / 1991} + 1ns, 16s);
|
||||
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::July / 1 / 1992} - 1ns, 16s);
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::July / 1 / 1992}, 17s);
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::July / 1 / 1992} + 1ns, 17s);
|
||||
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::July / 1 / 1993} - 1ns, 17s);
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::July / 1 / 1993}, 18s);
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::July / 1 / 1993} + 1ns, 18s);
|
||||
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::July / 1 / 1994} - 1ns, 18s);
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::July / 1 / 1994}, 19s);
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::July / 1 / 1994} + 1ns, 19s);
|
||||
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::January / 1 / 1996} - 1ns, 19s);
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::January / 1 / 1996}, 20s);
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::January / 1 / 1996} + 1ns, 20s);
|
||||
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::July / 1 / 1997} - 1ns, 20s);
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::July / 1 / 1997}, 21s);
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::July / 1 / 1997} + 1ns, 21s);
|
||||
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::January / 1 / 1999} - 1ns, 21s);
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::January / 1 / 1999}, 22s);
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::January / 1 / 1999} + 1ns, 22s);
|
||||
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::January / 1 / 2006} - 1ns, 22s);
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::January / 1 / 2006}, 23s);
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::January / 1 / 2006} + 1ns, 23s);
|
||||
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::January / 1 / 2009} - 1ns, 23s);
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::January / 1 / 2009}, 24s);
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::January / 1 / 2009} + 1ns, 24s);
|
||||
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::July / 1 / 2012} - 1ns, 24s);
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::July / 1 / 2012}, 25s);
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::July / 1 / 2012} + 1ns, 25s);
|
||||
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::July / 1 / 2015} - 1ns, 25s);
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::July / 1 / 2015}, 26s);
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::July / 1 / 2015} + 1ns, 26s);
|
||||
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::January / 1 / 2017} - 1ns, 26s);
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::January / 1 / 2017}, 27s);
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::January / 1 / 2017} + 1ns, 27s);
|
||||
|
||||
// This validates status when the tests were written.
|
||||
// It's not possible to test the future; there might be additional leap
|
||||
// seconds in the future.
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::January / 1 / 2024} - 1ns, 27s);
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::January / 1 / 2024}, 27s);
|
||||
test_leap_seconds(std::chrono::sys_days{std::chrono::January / 1 / 2024} + 1ns, 27s);
|
||||
}
|
||||
|
||||
// Tests whether the return type is the expected type.
|
||||
static void test_return_type() {
|
||||
namespace cr = std::chrono;
|
||||
using namespace std::literals::chrono_literals;
|
||||
|
||||
{
|
||||
[[maybe_unused]] std::same_as<cr::utc_time<cr::nanoseconds>> decltype(auto) _ =
|
||||
cr::utc_clock::from_sys(cr::sys_time<cr::nanoseconds>{0ns});
|
||||
}
|
||||
{
|
||||
[[maybe_unused]] std::same_as<cr::utc_time<cr::microseconds>> decltype(auto) _ =
|
||||
cr::utc_clock::from_sys(cr::sys_time<cr::microseconds>{0us});
|
||||
}
|
||||
{
|
||||
[[maybe_unused]] std::same_as<cr::utc_time<cr::milliseconds>> decltype(auto) _ =
|
||||
cr::utc_clock::from_sys(cr::sys_time<cr::milliseconds>{0ms});
|
||||
}
|
||||
|
||||
{
|
||||
[[maybe_unused]] std::same_as<cr::utc_time<cr::seconds>> decltype(auto) _ =
|
||||
cr::utc_clock::from_sys(cr::sys_time<cr::seconds>{cr::seconds{0}});
|
||||
}
|
||||
|
||||
{
|
||||
[[maybe_unused]] std::same_as<cr::utc_time<cr::seconds>> decltype(auto) _ =
|
||||
cr::utc_clock::from_sys(cr::sys_time<cr::minutes>{cr::minutes{0}});
|
||||
}
|
||||
{
|
||||
[[maybe_unused]] std::same_as<cr::utc_time<cr::seconds>> decltype(auto) _ =
|
||||
cr::utc_clock::from_sys(cr::sys_time<cr::hours>{cr::hours{0}});
|
||||
}
|
||||
{
|
||||
[[maybe_unused]] std::same_as<cr::utc_time<cr::seconds>> decltype(auto) _ =
|
||||
cr::utc_clock::from_sys(cr::sys_time<cr::days>{cr::days{0}});
|
||||
}
|
||||
{
|
||||
[[maybe_unused]] std::same_as<cr::utc_time<cr::seconds>> decltype(auto) _ =
|
||||
cr::utc_clock::from_sys(cr::sys_time<cr::weeks>{cr::weeks{0}});
|
||||
}
|
||||
{
|
||||
[[maybe_unused]] std::same_as<cr::utc_time<cr::seconds>> decltype(auto) _ =
|
||||
cr::utc_clock::from_sys(cr::sys_time<cr::months>{cr::months{0}});
|
||||
}
|
||||
{
|
||||
[[maybe_unused]] std::same_as<cr::utc_time<cr::seconds>> decltype(auto) _ =
|
||||
cr::utc_clock::from_sys(cr::sys_time<cr::years>{cr::years{0}});
|
||||
}
|
||||
}
|
||||
|
||||
int main(int, const char**) {
|
||||
test_example_standard();
|
||||
test_transitions();
|
||||
test_return_type();
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: no-filesystem, no-localization, no-tzdb
|
||||
|
||||
// XFAIL: libcpp-has-no-experimental-tzdb
|
||||
// XFAIL: availability-tzdb-missing
|
||||
|
||||
// <chrono>
|
||||
//
|
||||
// class utc_clock;
|
||||
|
||||
// static time_point now();
|
||||
|
||||
#include <chrono>
|
||||
#include <concepts>
|
||||
#include <cassert>
|
||||
|
||||
int main(int, const char**) {
|
||||
using clock = std::chrono::utc_clock;
|
||||
std::same_as<clock::time_point> decltype(auto) t = clock::now();
|
||||
|
||||
assert(t >= clock::time_point::min());
|
||||
assert(t <= clock::time_point::max());
|
||||
|
||||
auto t2 = clock::now();
|
||||
assert(t2 - t >= std::chrono::seconds(0));
|
||||
// This may fail if the tests takes a long time to complete.
|
||||
assert(t2 - t < std::chrono::seconds(42));
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,252 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: no-filesystem, no-localization, no-tzdb
|
||||
|
||||
// XFAIL: libcpp-has-no-experimental-tzdb
|
||||
// XFAIL: availability-tzdb-missing
|
||||
|
||||
// <chrono>
|
||||
|
||||
// class utc_clock;
|
||||
|
||||
// static sys_time<common_type_t<_Duration, seconds>>
|
||||
// to_sys(const utc_time<_Duration>& __time);
|
||||
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "assert_macros.h"
|
||||
#include "concat_macros.h"
|
||||
|
||||
template <class Duration>
|
||||
static void test_leap_seconds(std::chrono::utc_time<Duration> time, std::chrono::sys_time<Duration> expected) {
|
||||
auto result = std::chrono::utc_clock::to_sys(time);
|
||||
TEST_REQUIRE(
|
||||
result == expected,
|
||||
TEST_WRITE_CONCATENATED("\tTime: ", time, "\nExpected output ", expected, "\nActual output ", result, '\n'));
|
||||
}
|
||||
|
||||
static std::chrono::sys_seconds get_sys_time(long long seconds_since_1900) {
|
||||
// The file leap-seconds.list stores dates since 1 January 1900, 00:00:00, we want
|
||||
// seconds since 1 January 1970.
|
||||
constexpr auto offset =
|
||||
std::chrono::sys_days{std::chrono::January / 1 / 1970} - std::chrono::sys_days{std::chrono::January / 1 / 1900};
|
||||
return std::chrono::sys_seconds{std::chrono::seconds{seconds_since_1900} - offset};
|
||||
}
|
||||
|
||||
// Tests the set of existing database entries at the time of writing. Since
|
||||
// the last leap second insertion is several years ago, it's expected all
|
||||
// systems have the same information. (Adding new entries in the future does
|
||||
// not affect this test.)
|
||||
static void test_transitions() {
|
||||
using namespace std::literals::chrono_literals;
|
||||
|
||||
test_leap_seconds(std::chrono::utc_seconds::min(), std::chrono::sys_seconds::min());
|
||||
|
||||
// Epoch transition no transitions.
|
||||
test_leap_seconds(std::chrono::utc_seconds{-1s}, std::chrono::sys_seconds{-1s});
|
||||
test_leap_seconds(std::chrono::utc_seconds{0s}, std::chrono::sys_seconds{0s});
|
||||
test_leap_seconds(std::chrono::utc_seconds{1s}, std::chrono::sys_seconds{1s});
|
||||
|
||||
// "sys" is the time of the transition to the next leap second.
|
||||
// "elapsed" is the number of leap seconds before the transition.
|
||||
// "positive" is the leap second added +1s? If not it's -1s.
|
||||
auto test_transition = [](std::chrono::sys_seconds sys, std::chrono::seconds elapsed, bool positive) {
|
||||
// Note at the time of writing all leap seconds are positive so the else
|
||||
// branch is never executed. The private test for this function tests
|
||||
// negative leap seconds and uses the else branch.
|
||||
|
||||
std::chrono::utc_seconds utc = std::chrono::utc_seconds{sys.time_since_epoch()} + elapsed;
|
||||
if (positive) {
|
||||
// Every transition has the following tests
|
||||
// - 1ns before the start of the transition no adjustment needed
|
||||
// - at the start of the transition sys is clamped at the time just prior to the moment
|
||||
// of the leap second insertion. The exact value depends
|
||||
// on the resolution of the result type.
|
||||
// - 1ns before the end of the transition sys is still clamped like before
|
||||
// - at the end of the transition sys is 1s behind the utc time
|
||||
// - 1ns after the end of the transition sys is still 1s behind the utc time
|
||||
test_leap_seconds(utc - 1ns, sys - 1ns);
|
||||
test_leap_seconds(utc, sys - 1s);
|
||||
test_leap_seconds(utc + 0ns, sys - 1ns);
|
||||
test_leap_seconds(utc + 1s - 1ns, sys - 1ns);
|
||||
test_leap_seconds(utc + 1s, sys);
|
||||
test_leap_seconds(utc + 1s + 0ns, sys + 0ns);
|
||||
test_leap_seconds(utc + 1s + 1ns, sys + 1ns);
|
||||
} else {
|
||||
// Every transition has the following tests
|
||||
// - 1ns before the transition no adjustment needed
|
||||
// - at the transition sys is 1s ahead of the utc time
|
||||
// - 1ns after the transition sys is still 1s ahead of the utc time
|
||||
test_leap_seconds(utc - 1ns, sys - 1ns);
|
||||
test_leap_seconds(utc, sys + 1s);
|
||||
test_leap_seconds(utc + 1ns, sys + 1s + 1ns);
|
||||
}
|
||||
};
|
||||
|
||||
// Transitions from the start of UTC.
|
||||
test_transition(get_sys_time(2287785600), 0s, true); // 1 Jul 1972
|
||||
test_transition(get_sys_time(2303683200), 1s, true); // 1 Jan 1973
|
||||
test_transition(get_sys_time(2335219200), 2s, true); // 1 Jan 1974
|
||||
test_transition(get_sys_time(2366755200), 3s, true); // 1 Jan 1975
|
||||
test_transition(get_sys_time(2398291200), 4s, true); // 1 Jan 1976
|
||||
test_transition(get_sys_time(2429913600), 5s, true); // 1 Jan 1977
|
||||
test_transition(get_sys_time(2461449600), 6s, true); // 1 Jan 1978
|
||||
test_transition(get_sys_time(2492985600), 7s, true); // 1 Jan 1979
|
||||
test_transition(get_sys_time(2524521600), 8s, true); // 1 Jan 1980
|
||||
test_transition(get_sys_time(2571782400), 9s, true); // 1 Jul 1981
|
||||
test_transition(get_sys_time(2603318400), 10s, true); // 1 Jul 1982
|
||||
test_transition(get_sys_time(2634854400), 11s, true); // 1 Jul 1983
|
||||
test_transition(get_sys_time(2698012800), 12s, true); // 1 Jul 1985
|
||||
test_transition(get_sys_time(2776982400), 13s, true); // 1 Jan 1988
|
||||
test_transition(get_sys_time(2840140800), 14s, true); // 1 Jan 1990
|
||||
test_transition(get_sys_time(2871676800), 15s, true); // 1 Jan 1991
|
||||
test_transition(get_sys_time(2918937600), 16s, true); // 1 Jul 1992
|
||||
test_transition(get_sys_time(2950473600), 17s, true); // 1 Jul 1993
|
||||
test_transition(get_sys_time(2982009600), 18s, true); // 1 Jul 1994
|
||||
test_transition(get_sys_time(3029443200), 19s, true); // 1 Jan 1996
|
||||
test_transition(get_sys_time(3076704000), 20s, true); // 1 Jul 1997
|
||||
test_transition(get_sys_time(3124137600), 21s, true); // 1 Jan 1999
|
||||
test_transition(get_sys_time(3345062400), 22s, true); // 1 Jan 2006
|
||||
test_transition(get_sys_time(3439756800), 23s, true); // 1 Jan 2009
|
||||
test_transition(get_sys_time(3550089600), 24s, true); // 1 Jul 2012
|
||||
test_transition(get_sys_time(3644697600), 25s, true); // 1 Jul 2015
|
||||
test_transition(get_sys_time(3692217600), 26s, true); // 1 Jan 2017
|
||||
}
|
||||
|
||||
// Tests the transition for clocks where the duration's rep is a floating-point type.
|
||||
static void test_transitions_floating_point() {
|
||||
using namespace std::literals::chrono_literals;
|
||||
|
||||
// Based on test_transitions but uses a floating-point duration.
|
||||
using F = float;
|
||||
|
||||
auto test_transition = [](std::chrono::sys_seconds sys, std::chrono::seconds elapsed, bool positive) {
|
||||
// Note at the time of writing all leap seconds are positive so the else
|
||||
// branch is never executed. The private test for this function tests
|
||||
// negative leap seconds and uses the else branch.
|
||||
|
||||
std::chrono::utc_seconds utc = std::chrono::utc_seconds{sys.time_since_epoch()} + elapsed;
|
||||
|
||||
using D = std::chrono::duration<F>;
|
||||
using S = std::chrono ::time_point<std::chrono::system_clock, D>;
|
||||
using U = std::chrono ::time_point<std::chrono::utc_clock, D>;
|
||||
|
||||
S s{sys.time_since_epoch()};
|
||||
bool is_leap_second = s.time_since_epoch().count() == sys.time_since_epoch().count();
|
||||
assert(is_leap_second);
|
||||
|
||||
U u{utc.time_since_epoch()};
|
||||
if (positive) {
|
||||
test_leap_seconds(u - 1ns, s - 1ns);
|
||||
test_leap_seconds(u, s - 1s);
|
||||
test_leap_seconds(u + 0ns, s - 1ns);
|
||||
test_leap_seconds(u + 1s - 1ns, s - 1ns);
|
||||
test_leap_seconds(u + 1s, s);
|
||||
test_leap_seconds(u + 1s + 0ns, s + 0ns);
|
||||
test_leap_seconds(u + 1s + 1ns, s + 1ns);
|
||||
|
||||
test_leap_seconds(U{D{std::nextafter(u.time_since_epoch().count(), F{0})}},
|
||||
S{D{std::nextafter(s.time_since_epoch().count(), F{0})}});
|
||||
test_leap_seconds(u, S{D{s.time_since_epoch().count() - F{1}}});
|
||||
test_leap_seconds(U{D{u.time_since_epoch().count() + F{1}}}, s);
|
||||
test_leap_seconds(U{D{std::nextafter(u.time_since_epoch().count() + F{1}, std::numeric_limits<F>::max())}},
|
||||
S{D{std::nextafter(s.time_since_epoch().count(), std::numeric_limits<F>::max())}});
|
||||
}
|
||||
};
|
||||
|
||||
// Transitions from the start of UTC.
|
||||
test_transition(get_sys_time(2287785600), 0s, true); // 1 Jul 1972
|
||||
test_transition(get_sys_time(2303683200), 1s, true); // 1 Jan 1973
|
||||
test_transition(get_sys_time(2335219200), 2s, true); // 1 Jan 1974
|
||||
test_transition(get_sys_time(2366755200), 3s, true); // 1 Jan 1975
|
||||
test_transition(get_sys_time(2398291200), 4s, true); // 1 Jan 1976
|
||||
test_transition(get_sys_time(2429913600), 5s, true); // 1 Jan 1977
|
||||
test_transition(get_sys_time(2461449600), 6s, true); // 1 Jan 1978
|
||||
test_transition(get_sys_time(2492985600), 7s, true); // 1 Jan 1979
|
||||
test_transition(get_sys_time(2524521600), 8s, true); // 1 Jan 1980
|
||||
test_transition(get_sys_time(2571782400), 9s, true); // 1 Jul 1981
|
||||
test_transition(get_sys_time(2603318400), 10s, true); // 1 Jul 1982
|
||||
test_transition(get_sys_time(2634854400), 11s, true); // 1 Jul 1983
|
||||
test_transition(get_sys_time(2698012800), 12s, true); // 1 Jul 1985
|
||||
test_transition(get_sys_time(2776982400), 13s, true); // 1 Jan 1988
|
||||
test_transition(get_sys_time(2840140800), 14s, true); // 1 Jan 1990
|
||||
test_transition(get_sys_time(2871676800), 15s, true); // 1 Jan 1991
|
||||
test_transition(get_sys_time(2918937600), 16s, true); // 1 Jul 1992
|
||||
test_transition(get_sys_time(2950473600), 17s, true); // 1 Jul 1993
|
||||
test_transition(get_sys_time(2982009600), 18s, true); // 1 Jul 1994
|
||||
test_transition(get_sys_time(3029443200), 19s, true); // 1 Jan 1996
|
||||
test_transition(get_sys_time(3076704000), 20s, true); // 1 Jul 1997
|
||||
test_transition(get_sys_time(3124137600), 21s, true); // 1 Jan 1999
|
||||
test_transition(get_sys_time(3345062400), 22s, true); // 1 Jan 2006
|
||||
test_transition(get_sys_time(3439756800), 23s, true); // 1 Jan 2009
|
||||
test_transition(get_sys_time(3550089600), 24s, true); // 1 Jul 2012
|
||||
test_transition(get_sys_time(3644697600), 25s, true); // 1 Jul 2015
|
||||
test_transition(get_sys_time(3692217600), 26s, true); // 1 Jan 2017
|
||||
}
|
||||
|
||||
// Tests whether the return type is the expected type.
|
||||
static void test_return_type() {
|
||||
namespace cr = std::chrono;
|
||||
using namespace std::literals::chrono_literals;
|
||||
|
||||
{
|
||||
[[maybe_unused]] std::same_as<cr::sys_time<cr::nanoseconds>> decltype(auto) _ =
|
||||
cr::utc_clock::to_sys(cr::utc_time<cr::nanoseconds>{0ns});
|
||||
}
|
||||
{
|
||||
[[maybe_unused]] std::same_as<cr::sys_time<cr::microseconds>> decltype(auto) _ =
|
||||
cr::utc_clock::to_sys(cr::utc_time<cr::microseconds>{0us});
|
||||
}
|
||||
{
|
||||
[[maybe_unused]] std::same_as<cr::sys_time<cr::milliseconds>> decltype(auto) _ =
|
||||
cr::utc_clock::to_sys(cr::utc_time<cr::milliseconds>{0ms});
|
||||
}
|
||||
|
||||
{
|
||||
[[maybe_unused]] std::same_as<cr::sys_time<cr::seconds>> decltype(auto) _ =
|
||||
cr::utc_clock::to_sys(cr::utc_time<cr::seconds>{cr::seconds{0}});
|
||||
}
|
||||
|
||||
{
|
||||
[[maybe_unused]] std::same_as<cr::sys_time<cr::seconds>> decltype(auto) _ =
|
||||
cr::utc_clock::to_sys(cr::utc_time<cr::minutes>{cr::minutes{0}});
|
||||
}
|
||||
{
|
||||
[[maybe_unused]] std::same_as<cr::sys_time<cr::seconds>> decltype(auto) _ =
|
||||
cr::utc_clock::to_sys(cr::utc_time<cr::hours>{cr::hours{0}});
|
||||
}
|
||||
{
|
||||
[[maybe_unused]] std::same_as<cr::sys_time<cr::seconds>> decltype(auto) _ =
|
||||
cr::utc_clock::to_sys(cr::utc_time<cr::days>{cr::days{0}});
|
||||
}
|
||||
{
|
||||
[[maybe_unused]] std::same_as<cr::sys_time<cr::seconds>> decltype(auto) _ =
|
||||
cr::utc_clock::to_sys(cr::utc_time<cr::weeks>{cr::weeks{0}});
|
||||
}
|
||||
{
|
||||
[[maybe_unused]] std::same_as<cr::sys_time<cr::seconds>> decltype(auto) _ =
|
||||
cr::utc_clock::to_sys(cr::utc_time<cr::months>{cr::months{0}});
|
||||
}
|
||||
{
|
||||
[[maybe_unused]] std::same_as<cr::sys_time<cr::seconds>> decltype(auto) _ =
|
||||
cr::utc_clock::to_sys(cr::utc_time<cr::years>{cr::years{0}});
|
||||
}
|
||||
}
|
||||
|
||||
int main(int, const char**) {
|
||||
test_transitions();
|
||||
test_transitions_floating_point();
|
||||
test_return_type();
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: no-filesystem, no-localization, no-tzdb
|
||||
|
||||
// XFAIL: libcpp-has-no-experimental-tzdb
|
||||
// XFAIL: availability-tzdb-missing
|
||||
|
||||
// <chrono>
|
||||
|
||||
// class utc_clock {
|
||||
// public:
|
||||
// using rep = a signed arithmetic type;
|
||||
// using period = ratio<unspecified, unspecified>;
|
||||
// using duration = chrono::duration<rep, period>;
|
||||
// using time_point = chrono::time_point<utc_clock>;
|
||||
// static constexpr bool is_steady = unspecified;
|
||||
//
|
||||
// ...
|
||||
// };
|
||||
//
|
||||
// template<class Duration>
|
||||
// using utc_time = time_point<utc_clock, Duration>;
|
||||
// using utc_seconds = utc_time<seconds>;
|
||||
|
||||
#include <concepts>
|
||||
#include <chrono>
|
||||
#include <ratio>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
// class utc_clock
|
||||
using rep = std::chrono::utc_clock::rep;
|
||||
using period = std::chrono::utc_clock::period;
|
||||
using duration = std::chrono::utc_clock::duration;
|
||||
using time_point = std::chrono::utc_clock::time_point;
|
||||
constexpr bool is_steady = std::chrono::utc_clock::is_steady;
|
||||
|
||||
// Tests the values. Some of them are implementation-defined.
|
||||
LIBCPP_STATIC_ASSERT(std::same_as<rep, std::chrono::system_clock::rep>);
|
||||
static_assert(std::is_arithmetic_v<rep>);
|
||||
static_assert(std::is_signed_v<rep>);
|
||||
|
||||
LIBCPP_STATIC_ASSERT(std::same_as<period, std::chrono::system_clock::period>);
|
||||
static_assert(std::same_as<period, std::ratio<period::num, period::den>>);
|
||||
|
||||
static_assert(std::same_as<duration, std::chrono::duration<rep, period>>);
|
||||
static_assert(std::same_as<time_point, std::chrono::time_point<std::chrono::utc_clock>>);
|
||||
LIBCPP_STATIC_ASSERT(is_steady == false);
|
||||
|
||||
// typedefs
|
||||
static_assert(std::same_as<std::chrono::utc_time<int>, std::chrono::time_point<std::chrono::utc_clock, int>>);
|
||||
static_assert(std::same_as<std::chrono::utc_time<long>, std::chrono::time_point<std::chrono::utc_clock, long>>);
|
||||
static_assert(std::same_as<std::chrono::utc_seconds, std::chrono::utc_time<std::chrono::seconds>>);
|
@ -0,0 +1,165 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: no-filesystem, no-localization, no-tzdb
|
||||
// UNSUPPORTED: GCC-ALWAYS_INLINE-FIXME
|
||||
|
||||
// TODO FMT This test should not require std::to_chars(floating-point)
|
||||
// XFAIL: availability-fp_to_chars-missing
|
||||
|
||||
// XFAIL: libcpp-has-no-experimental-tzdb
|
||||
// XFAIL: availability-tzdb-missing
|
||||
|
||||
// REQUIRES: locale.fr_FR.UTF-8
|
||||
// REQUIRES: locale.ja_JP.UTF-8
|
||||
|
||||
// <chrono>
|
||||
|
||||
// using utc_time = ...;
|
||||
|
||||
// template<class charT, class traits, class Duration>
|
||||
// basic_ostream<charT, traits>&
|
||||
// operator<<(basic_ostream<charT, traits>& os, const utc_time<Duration>& tp);
|
||||
|
||||
#include <chrono>
|
||||
#include <cassert>
|
||||
#include <ratio>
|
||||
#include <sstream>
|
||||
|
||||
#include "make_string.h"
|
||||
#include "platform_support.h" // locale name macros
|
||||
#include "test_macros.h"
|
||||
|
||||
#define SV(S) MAKE_STRING_VIEW(CharT, S)
|
||||
|
||||
template <class CharT, class Duration>
|
||||
static std::basic_string<CharT> stream_c_locale(std::chrono::utc_time<Duration> time_point) {
|
||||
std::basic_stringstream<CharT> sstr;
|
||||
sstr << std::fixed << time_point;
|
||||
return sstr.str();
|
||||
}
|
||||
|
||||
template <class CharT, class Duration>
|
||||
static std::basic_string<CharT> stream_fr_FR_locale(std::chrono::utc_time<Duration> time_point) {
|
||||
std::basic_stringstream<CharT> sstr;
|
||||
const std::locale locale(LOCALE_fr_FR_UTF_8);
|
||||
sstr.imbue(locale);
|
||||
sstr << std::fixed << time_point;
|
||||
return sstr.str();
|
||||
}
|
||||
|
||||
template <class CharT, class Duration>
|
||||
static std::basic_string<CharT> stream_ja_JP_locale(std::chrono::utc_time<Duration> time_point) {
|
||||
std::basic_stringstream<CharT> sstr;
|
||||
const std::locale locale(LOCALE_ja_JP_UTF_8);
|
||||
sstr.imbue(locale);
|
||||
sstr << std::fixed << time_point;
|
||||
return sstr.str();
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
static void test_c() {
|
||||
using namespace std::literals::chrono_literals;
|
||||
|
||||
assert(stream_c_locale<CharT>(std::chrono::utc_time<std::chrono::nanoseconds>{946'688'523'123'456'789ns}) ==
|
||||
SV("2000-01-01 01:01:41.123456789"));
|
||||
assert(stream_c_locale<CharT>(std::chrono::utc_time<std::chrono::microseconds>{946'688'523'123'456us}) ==
|
||||
SV("2000-01-01 01:01:41.123456"));
|
||||
|
||||
assert(stream_c_locale<CharT>(std::chrono::utc_time<std::chrono::milliseconds>{946'684'822'123ms}) ==
|
||||
SV("2000-01-01 00:00:00.123"));
|
||||
assert(stream_c_locale<CharT>(std::chrono::utc_seconds{1'234'567'890s}) == SV("2009-02-13 23:31:06"));
|
||||
assert(stream_c_locale<CharT>(std::chrono::utc_time<std::chrono::minutes>{20'576'131min}) ==
|
||||
SV("2009-02-13 23:30:36"));
|
||||
assert(stream_c_locale<CharT>(std::chrono::utc_time<std::chrono::hours>{342'935h}) == SV("2009-02-13 22:59:36"));
|
||||
|
||||
assert(stream_c_locale<CharT>(std::chrono::utc_time<std::chrono::duration<signed char, std::ratio<2, 1>>>{
|
||||
std::chrono::duration<signed char, std::ratio<2, 1>>{60}}) == SV("1970-01-01 00:02:00"));
|
||||
assert(stream_c_locale<CharT>(std::chrono::utc_time<std::chrono::duration<short, std::ratio<1, 2>>>{
|
||||
std::chrono::duration<short, std::ratio<1, 2>>{3600}}) == SV("1970-01-01 00:30:00.0"));
|
||||
assert(stream_c_locale<CharT>(std::chrono::utc_time<std::chrono::duration<int, std::ratio<1, 4>>>{
|
||||
std::chrono::duration<int, std::ratio<1, 4>>{3600}}) == SV("1970-01-01 00:15:00.00"));
|
||||
assert(stream_c_locale<CharT>(std::chrono::utc_time<std::chrono::duration<long, std::ratio<1, 10>>>{
|
||||
std::chrono::duration<long, std::ratio<1, 10>>{36611}}) == SV("1970-01-01 01:01:01.1"));
|
||||
assert(stream_c_locale<CharT>(std::chrono::utc_time<std::chrono::duration<long long, std::ratio<1, 100>>>{
|
||||
std::chrono::duration<long long, std::ratio<1, 100>>{12'345'678'9010}}) == SV("2009-02-13 23:31:06.10"));
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
static void test_fr_FR() {
|
||||
using namespace std::literals::chrono_literals;
|
||||
|
||||
assert(stream_fr_FR_locale<CharT>(std::chrono::utc_time<std::chrono::nanoseconds>{946'688'523'123'456'789ns}) ==
|
||||
SV("2000-01-01 01:01:41,123456789"));
|
||||
assert(stream_fr_FR_locale<CharT>(std::chrono::utc_time<std::chrono::microseconds>{946'688'523'123'456us}) ==
|
||||
SV("2000-01-01 01:01:41,123456"));
|
||||
|
||||
assert(stream_fr_FR_locale<CharT>(std::chrono::utc_time<std::chrono::milliseconds>{946'684'822'123ms}) ==
|
||||
SV("2000-01-01 00:00:00,123"));
|
||||
assert(stream_fr_FR_locale<CharT>(std::chrono::utc_seconds{1'234'567'890s}) == SV("2009-02-13 23:31:06"));
|
||||
assert(stream_fr_FR_locale<CharT>(std::chrono::utc_time<std::chrono::minutes>{20'576'131min}) ==
|
||||
SV("2009-02-13 23:30:36"));
|
||||
assert(stream_fr_FR_locale<CharT>(std::chrono::utc_time<std::chrono::hours>{342'935h}) == SV("2009-02-13 22:59:36"));
|
||||
|
||||
assert(stream_fr_FR_locale<CharT>(std::chrono::utc_time<std::chrono::duration<signed char, std::ratio<2, 1>>>{
|
||||
std::chrono::duration<signed char, std::ratio<2, 1>>{60}}) == SV("1970-01-01 00:02:00"));
|
||||
assert(stream_fr_FR_locale<CharT>(std::chrono::utc_time<std::chrono::duration<short, std::ratio<1, 2>>>{
|
||||
std::chrono::duration<short, std::ratio<1, 2>>{3600}}) == SV("1970-01-01 00:30:00,0"));
|
||||
assert(stream_fr_FR_locale<CharT>(std::chrono::utc_time<std::chrono::duration<int, std::ratio<1, 4>>>{
|
||||
std::chrono::duration<int, std::ratio<1, 4>>{3600}}) == SV("1970-01-01 00:15:00,00"));
|
||||
assert(stream_fr_FR_locale<CharT>(std::chrono::utc_time<std::chrono::duration<long, std::ratio<1, 10>>>{
|
||||
std::chrono::duration<long, std::ratio<1, 10>>{36611}}) == SV("1970-01-01 01:01:01,1"));
|
||||
assert(stream_fr_FR_locale<CharT>(std::chrono::utc_time<std::chrono::duration<long long, std::ratio<1, 100>>>{
|
||||
std::chrono::duration<long long, std::ratio<1, 100>>{12'345'678'9010}}) == SV("2009-02-13 23:31:06,10"));
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
static void test_ja_JP() {
|
||||
using namespace std::literals::chrono_literals;
|
||||
|
||||
assert(stream_ja_JP_locale<CharT>(std::chrono::utc_time<std::chrono::nanoseconds>{946'688'523'123'456'789ns}) ==
|
||||
SV("2000-01-01 01:01:41.123456789"));
|
||||
assert(stream_ja_JP_locale<CharT>(std::chrono::utc_time<std::chrono::microseconds>{946'688'523'123'456us}) ==
|
||||
SV("2000-01-01 01:01:41.123456"));
|
||||
|
||||
assert(stream_ja_JP_locale<CharT>(std::chrono::utc_time<std::chrono::milliseconds>{946'684'822'123ms}) ==
|
||||
SV("2000-01-01 00:00:00.123"));
|
||||
assert(stream_ja_JP_locale<CharT>(std::chrono::utc_seconds{1'234'567'890s}) == SV("2009-02-13 23:31:06"));
|
||||
assert(stream_ja_JP_locale<CharT>(std::chrono::utc_time<std::chrono::minutes>{20'576'131min}) ==
|
||||
SV("2009-02-13 23:30:36"));
|
||||
assert(stream_ja_JP_locale<CharT>(std::chrono::utc_time<std::chrono::hours>{342'935h}) == SV("2009-02-13 22:59:36"));
|
||||
|
||||
assert(stream_ja_JP_locale<CharT>(std::chrono::utc_time<std::chrono::duration<signed char, std::ratio<2, 1>>>{
|
||||
std::chrono::duration<signed char, std::ratio<2, 1>>{60}}) == SV("1970-01-01 00:02:00"));
|
||||
assert(stream_ja_JP_locale<CharT>(std::chrono::utc_time<std::chrono::duration<short, std::ratio<1, 2>>>{
|
||||
std::chrono::duration<short, std::ratio<1, 2>>{3600}}) == SV("1970-01-01 00:30:00.0"));
|
||||
assert(stream_ja_JP_locale<CharT>(std::chrono::utc_time<std::chrono::duration<int, std::ratio<1, 4>>>{
|
||||
std::chrono::duration<int, std::ratio<1, 4>>{3600}}) == SV("1970-01-01 00:15:00.00"));
|
||||
assert(stream_ja_JP_locale<CharT>(std::chrono::utc_time<std::chrono::duration<long, std::ratio<1, 10>>>{
|
||||
std::chrono::duration<long, std::ratio<1, 10>>{36611}}) == SV("1970-01-01 01:01:01.1"));
|
||||
assert(stream_ja_JP_locale<CharT>(std::chrono::utc_time<std::chrono::duration<long long, std::ratio<1, 100>>>{
|
||||
std::chrono::duration<long long, std::ratio<1, 100>>{12'345'678'9010}}) == SV("2009-02-13 23:31:06.10"));
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
static void test() {
|
||||
test_c<CharT>();
|
||||
test_fr_FR<CharT>();
|
||||
test_ja_JP<CharT>();
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test<char>();
|
||||
|
||||
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
|
||||
test<wchar_t>();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
1004
libcxx/test/std/time/time.syn/formatter.utc_time.pass.cpp
Normal file
1004
libcxx/test/std/time/time.syn/formatter.utc_time.pass.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@ -150,9 +150,15 @@ void test_P1361() {
|
||||
assert_is_formattable<std::chrono::microseconds, CharT>();
|
||||
|
||||
assert_is_formattable<std::chrono::sys_time<std::chrono::microseconds>, CharT>();
|
||||
//assert_is_formattable<std::chrono::utc_time<std::chrono::microseconds>, CharT>();
|
||||
# if !defined(TEST_HAS_NO_EXPERIMENTAL_TZDB) && !defined(TEST_HAS_NO_TIME_ZONE_DATABASE) && \
|
||||
!defined(TEST_HAS_NO_FILESYSTEM)
|
||||
assert_is_formattable<std::chrono::utc_time<std::chrono::microseconds>, CharT>();
|
||||
//assert_is_formattable<std::chrono::tai_time<std::chrono::microseconds>, CharT>();
|
||||
//assert_is_formattable<std::chrono::gps_time<std::chrono::microseconds>, CharT>();
|
||||
|
||||
# endif // !defined(TEST_HAS_NO_EXPERIMENTAL_TZDB) && !defined(TEST_HAS_NO_TIME_ZONE_DATABASE) &&
|
||||
// !defined(TEST_HAS_NO_FILESYSTEM)
|
||||
|
||||
assert_is_formattable<std::chrono::file_time<std::chrono::microseconds>, CharT>();
|
||||
assert_is_formattable<std::chrono::local_time<std::chrono::microseconds>, CharT>();
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user