253 lines · cpp
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//===----------------------------------------------------------------------===//8 9// UNSUPPORTED: c++03, c++11, c++14, c++1710// UNSUPPORTED: no-filesystem, no-localization, no-tzdb11 12// XFAIL: libcpp-has-no-experimental-tzdb13// XFAIL: availability-tzdb-missing14 15// <chrono>16 17// class utc_clock;18 19// static sys_time<common_type_t<_Duration, seconds>>20// to_sys(const utc_time<_Duration>& __time);21 22#include <chrono>23#include <cmath>24#include <cassert>25 26#include "test_macros.h"27#include "assert_macros.h"28#include "concat_macros.h"29 30template <class Duration>31static void test_leap_seconds(std::chrono::utc_time<Duration> time, std::chrono::sys_time<Duration> expected) {32 auto result = std::chrono::utc_clock::to_sys(time);33 TEST_REQUIRE(34 result == expected,35 TEST_WRITE_CONCATENATED("\tTime: ", time, "\nExpected output ", expected, "\nActual output ", result, '\n'));36}37 38static std::chrono::sys_seconds get_sys_time(long long seconds_since_1900) {39 // The file leap-seconds.list stores dates since 1 January 1900, 00:00:00, we want40 // seconds since 1 January 1970.41 constexpr auto offset =42 std::chrono::sys_days{std::chrono::January / 1 / 1970} - std::chrono::sys_days{std::chrono::January / 1 / 1900};43 return std::chrono::sys_seconds{std::chrono::seconds{seconds_since_1900} - offset};44}45 46// Tests the set of existing database entries at the time of writing. Since47// the last leap second insertion is several years ago, it's expected all48// systems have the same information. (Adding new entries in the future does49// not affect this test.)50static void test_transitions() {51 using namespace std::literals::chrono_literals;52 53 test_leap_seconds(std::chrono::utc_seconds::min(), std::chrono::sys_seconds::min());54 55 // Epoch transition no transitions.56 test_leap_seconds(std::chrono::utc_seconds{-1s}, std::chrono::sys_seconds{-1s});57 test_leap_seconds(std::chrono::utc_seconds{0s}, std::chrono::sys_seconds{0s});58 test_leap_seconds(std::chrono::utc_seconds{1s}, std::chrono::sys_seconds{1s});59 60 // "sys" is the time of the transition to the next leap second.61 // "elapsed" is the number of leap seconds before the transition.62 // "positive" is the leap second added +1s? If not it's -1s.63 auto test_transition = [](std::chrono::sys_seconds sys, std::chrono::seconds elapsed, bool positive) {64 // Note at the time of writing all leap seconds are positive so the else65 // branch is never executed. The private test for this function tests66 // negative leap seconds and uses the else branch.67 68 std::chrono::utc_seconds utc = std::chrono::utc_seconds{sys.time_since_epoch()} + elapsed;69 if (positive) {70 // Every transition has the following tests71 // - 1ns before the start of the transition no adjustment needed72 // - at the start of the transition sys is clamped at the time just prior to the moment73 // of the leap second insertion. The exact value depends74 // on the resolution of the result type.75 // - 1ns before the end of the transition sys is still clamped like before76 // - at the end of the transition sys is 1s behind the utc time77 // - 1ns after the end of the transition sys is still 1s behind the utc time78 test_leap_seconds(utc - 1ns, sys - 1ns);79 test_leap_seconds(utc, sys - 1s);80 test_leap_seconds(utc + 0ns, sys - 1ns);81 test_leap_seconds(utc + 1s - 1ns, sys - 1ns);82 test_leap_seconds(utc + 1s, sys);83 test_leap_seconds(utc + 1s + 0ns, sys + 0ns);84 test_leap_seconds(utc + 1s + 1ns, sys + 1ns);85 } else {86 // Every transition has the following tests87 // - 1ns before the transition no adjustment needed88 // - at the transition sys is 1s ahead of the utc time89 // - 1ns after the transition sys is still 1s ahead of the utc time90 test_leap_seconds(utc - 1ns, sys - 1ns);91 test_leap_seconds(utc, sys + 1s);92 test_leap_seconds(utc + 1ns, sys + 1s + 1ns);93 }94 };95 96 // Transitions from the start of UTC.97 test_transition(get_sys_time(2287785600), 0s, true); // 1 Jul 197298 test_transition(get_sys_time(2303683200), 1s, true); // 1 Jan 197399 test_transition(get_sys_time(2335219200), 2s, true); // 1 Jan 1974100 test_transition(get_sys_time(2366755200), 3s, true); // 1 Jan 1975101 test_transition(get_sys_time(2398291200), 4s, true); // 1 Jan 1976102 test_transition(get_sys_time(2429913600), 5s, true); // 1 Jan 1977103 test_transition(get_sys_time(2461449600), 6s, true); // 1 Jan 1978104 test_transition(get_sys_time(2492985600), 7s, true); // 1 Jan 1979105 test_transition(get_sys_time(2524521600), 8s, true); // 1 Jan 1980106 test_transition(get_sys_time(2571782400), 9s, true); // 1 Jul 1981107 test_transition(get_sys_time(2603318400), 10s, true); // 1 Jul 1982108 test_transition(get_sys_time(2634854400), 11s, true); // 1 Jul 1983109 test_transition(get_sys_time(2698012800), 12s, true); // 1 Jul 1985110 test_transition(get_sys_time(2776982400), 13s, true); // 1 Jan 1988111 test_transition(get_sys_time(2840140800), 14s, true); // 1 Jan 1990112 test_transition(get_sys_time(2871676800), 15s, true); // 1 Jan 1991113 test_transition(get_sys_time(2918937600), 16s, true); // 1 Jul 1992114 test_transition(get_sys_time(2950473600), 17s, true); // 1 Jul 1993115 test_transition(get_sys_time(2982009600), 18s, true); // 1 Jul 1994116 test_transition(get_sys_time(3029443200), 19s, true); // 1 Jan 1996117 test_transition(get_sys_time(3076704000), 20s, true); // 1 Jul 1997118 test_transition(get_sys_time(3124137600), 21s, true); // 1 Jan 1999119 test_transition(get_sys_time(3345062400), 22s, true); // 1 Jan 2006120 test_transition(get_sys_time(3439756800), 23s, true); // 1 Jan 2009121 test_transition(get_sys_time(3550089600), 24s, true); // 1 Jul 2012122 test_transition(get_sys_time(3644697600), 25s, true); // 1 Jul 2015123 test_transition(get_sys_time(3692217600), 26s, true); // 1 Jan 2017124}125 126// Tests the transition for clocks where the duration's rep is a floating-point type.127static void test_transitions_floating_point() {128 using namespace std::literals::chrono_literals;129 130 // Based on test_transitions but uses a floating-point duration.131 using F = float;132 133 auto test_transition = [](std::chrono::sys_seconds sys, std::chrono::seconds elapsed, bool positive) {134 // Note at the time of writing all leap seconds are positive so the else135 // branch is never executed. The private test for this function tests136 // negative leap seconds and uses the else branch.137 138 std::chrono::utc_seconds utc = std::chrono::utc_seconds{sys.time_since_epoch()} + elapsed;139 140 using D = std::chrono::duration<F>;141 using S = std::chrono ::time_point<std::chrono::system_clock, D>;142 using U = std::chrono ::time_point<std::chrono::utc_clock, D>;143 144 S s{sys.time_since_epoch()};145 bool is_leap_second = s.time_since_epoch().count() == sys.time_since_epoch().count();146 assert(is_leap_second);147 148 U u{utc.time_since_epoch()};149 if (positive) {150 test_leap_seconds(u - 1ns, s - 1ns);151 test_leap_seconds(u, s - 1s);152 test_leap_seconds(u + 0ns, s - 1ns);153 test_leap_seconds(u + 1s - 1ns, s - 1ns);154 test_leap_seconds(u + 1s, s);155 test_leap_seconds(u + 1s + 0ns, s + 0ns);156 test_leap_seconds(u + 1s + 1ns, s + 1ns);157 158 test_leap_seconds(U{D{std::nextafter(u.time_since_epoch().count(), F{0})}},159 S{D{std::nextafter(s.time_since_epoch().count(), F{0})}});160 test_leap_seconds(u, S{D{s.time_since_epoch().count() - F{1}}});161 test_leap_seconds(U{D{u.time_since_epoch().count() + F{1}}}, s);162 test_leap_seconds(U{D{std::nextafter(u.time_since_epoch().count() + F{1}, std::numeric_limits<F>::max())}},163 S{D{std::nextafter(s.time_since_epoch().count(), std::numeric_limits<F>::max())}});164 }165 };166 167 // Transitions from the start of UTC.168 test_transition(get_sys_time(2287785600), 0s, true); // 1 Jul 1972169 test_transition(get_sys_time(2303683200), 1s, true); // 1 Jan 1973170 test_transition(get_sys_time(2335219200), 2s, true); // 1 Jan 1974171 test_transition(get_sys_time(2366755200), 3s, true); // 1 Jan 1975172 test_transition(get_sys_time(2398291200), 4s, true); // 1 Jan 1976173 test_transition(get_sys_time(2429913600), 5s, true); // 1 Jan 1977174 test_transition(get_sys_time(2461449600), 6s, true); // 1 Jan 1978175 test_transition(get_sys_time(2492985600), 7s, true); // 1 Jan 1979176 test_transition(get_sys_time(2524521600), 8s, true); // 1 Jan 1980177 test_transition(get_sys_time(2571782400), 9s, true); // 1 Jul 1981178 test_transition(get_sys_time(2603318400), 10s, true); // 1 Jul 1982179 test_transition(get_sys_time(2634854400), 11s, true); // 1 Jul 1983180 test_transition(get_sys_time(2698012800), 12s, true); // 1 Jul 1985181 test_transition(get_sys_time(2776982400), 13s, true); // 1 Jan 1988182 test_transition(get_sys_time(2840140800), 14s, true); // 1 Jan 1990183 test_transition(get_sys_time(2871676800), 15s, true); // 1 Jan 1991184 test_transition(get_sys_time(2918937600), 16s, true); // 1 Jul 1992185 test_transition(get_sys_time(2950473600), 17s, true); // 1 Jul 1993186 test_transition(get_sys_time(2982009600), 18s, true); // 1 Jul 1994187 test_transition(get_sys_time(3029443200), 19s, true); // 1 Jan 1996188 test_transition(get_sys_time(3076704000), 20s, true); // 1 Jul 1997189 test_transition(get_sys_time(3124137600), 21s, true); // 1 Jan 1999190 test_transition(get_sys_time(3345062400), 22s, true); // 1 Jan 2006191 test_transition(get_sys_time(3439756800), 23s, true); // 1 Jan 2009192 test_transition(get_sys_time(3550089600), 24s, true); // 1 Jul 2012193 test_transition(get_sys_time(3644697600), 25s, true); // 1 Jul 2015194 test_transition(get_sys_time(3692217600), 26s, true); // 1 Jan 2017195}196 197// Tests whether the return type is the expected type.198static void test_return_type() {199 namespace cr = std::chrono;200 using namespace std::literals::chrono_literals;201 202 {203 [[maybe_unused]] std::same_as<cr::sys_time<cr::nanoseconds>> decltype(auto) _ =204 cr::utc_clock::to_sys(cr::utc_time<cr::nanoseconds>{0ns});205 }206 {207 [[maybe_unused]] std::same_as<cr::sys_time<cr::microseconds>> decltype(auto) _ =208 cr::utc_clock::to_sys(cr::utc_time<cr::microseconds>{0us});209 }210 {211 [[maybe_unused]] std::same_as<cr::sys_time<cr::milliseconds>> decltype(auto) _ =212 cr::utc_clock::to_sys(cr::utc_time<cr::milliseconds>{0ms});213 }214 215 {216 [[maybe_unused]] std::same_as<cr::sys_time<cr::seconds>> decltype(auto) _ =217 cr::utc_clock::to_sys(cr::utc_time<cr::seconds>{cr::seconds{0}});218 }219 220 {221 [[maybe_unused]] std::same_as<cr::sys_time<cr::seconds>> decltype(auto) _ =222 cr::utc_clock::to_sys(cr::utc_time<cr::minutes>{cr::minutes{0}});223 }224 {225 [[maybe_unused]] std::same_as<cr::sys_time<cr::seconds>> decltype(auto) _ =226 cr::utc_clock::to_sys(cr::utc_time<cr::hours>{cr::hours{0}});227 }228 {229 [[maybe_unused]] std::same_as<cr::sys_time<cr::seconds>> decltype(auto) _ =230 cr::utc_clock::to_sys(cr::utc_time<cr::days>{cr::days{0}});231 }232 {233 [[maybe_unused]] std::same_as<cr::sys_time<cr::seconds>> decltype(auto) _ =234 cr::utc_clock::to_sys(cr::utc_time<cr::weeks>{cr::weeks{0}});235 }236 {237 [[maybe_unused]] std::same_as<cr::sys_time<cr::seconds>> decltype(auto) _ =238 cr::utc_clock::to_sys(cr::utc_time<cr::months>{cr::months{0}});239 }240 {241 [[maybe_unused]] std::same_as<cr::sys_time<cr::seconds>> decltype(auto) _ =242 cr::utc_clock::to_sys(cr::utc_time<cr::years>{cr::years{0}});243 }244}245 246int main(int, const char**) {247 test_transitions();248 test_transitions_floating_point();249 test_return_type();250 251 return 0;252}253