//===----------------------------------------------------------------------===// // // 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 // //===----------------------------------------------------------------------===// // REQUIRES: std-at-least-c++20 // UNSUPPORTED: no-filesystem, no-localization, no-tzdb // XFAIL: libcpp-has-no-experimental-tzdb // XFAIL: availability-tzdb-missing // // // class gps_clock; // static gps_time> // from_utc(const utc<_Duration>& __time) noexcept; #include #include #include #include "test_macros.h" #include "assert_macros.h" #include "concat_macros.h" static void test_known_values() { namespace cr = std::chrono; using namespace std::literals::chrono_literals; // [time.clock.gps.overview]/1 // The clock gps_clock measures seconds since the first Sunday of January, // 1980 00:00:00 UTC. // The first Sunday is 1980-1-6 (so January sixth) // ... 1980-01-06 00:00:00 GPS is equivalent to 1980-01-06 00:00:00 UTC assert(cr::gps_clock::from_utc(cr::utc_clock::from_sys(cr::sys_days{cr::January / 6 / 1980})) == cr::gps_seconds{0s}); } template static void test_leap_seconds(std::chrono::utc_time utc, std::chrono::gps_time expected, std::source_location loc = std::source_location::current()) { auto gps = std::chrono::gps_clock::from_utc(utc); TEST_REQUIRE(gps == expected, TEST_WRITE_CONCATENATED(loc, "\nExpected output ", expected, "\nActual output ", gps, '\n')); } // Tests set if existing database entries at the time of writing. static void test_transitions() { using namespace std::literals::chrono_literals; namespace cr = std::chrono; // "sys" is the time of the transition to the next leap second. // "elapsed" is the number of leap seconds before the transition. auto test_transition = [](cr::sys_days sys, cr::seconds elapsed) { constexpr auto unix_to_gps_epoch_offset = cr::sys_days{cr::January / 1 / 1970} - cr::sys_days{cr::January / 6 / 1980}; cr::gps_seconds gps{sys.time_since_epoch() + unix_to_gps_epoch_offset + elapsed}; test_leap_seconds(cr::utc_clock::from_sys(sys - 1ns), gps - 1ns); test_leap_seconds(cr::utc_clock::from_sys(sys), gps + 1s); test_leap_seconds(cr::utc_clock::from_sys(sys) + 1ns, gps + 1s + 1ns); }; // Transitions from the start of UTC. test_transition(cr::sys_days{cr::July / 1 / 1972}, -9s); test_transition(cr::sys_days{cr::January / 1 / 1973}, -8s); test_transition(cr::sys_days{cr::January / 1 / 1974}, -7s); test_transition(cr::sys_days{cr::January / 1 / 1975}, -6s); test_transition(cr::sys_days{cr::January / 1 / 1976}, -5s); test_transition(cr::sys_days{cr::January / 1 / 1977}, -4s); test_transition(cr::sys_days{cr::January / 1 / 1978}, -3s); test_transition(cr::sys_days{cr::January / 1 / 1979}, -2s); test_transition(cr::sys_days{cr::January / 1 / 1980}, -1s); test_transition(cr::sys_days{cr::July / 1 / 1981}, 0s); test_transition(cr::sys_days{cr::July / 1 / 1982}, 1s); test_transition(cr::sys_days{cr::July / 1 / 1983}, 2s); test_transition(cr::sys_days{cr::July / 1 / 1985}, 3s); test_transition(cr::sys_days{cr::January / 1 / 1988}, 4s); test_transition(cr::sys_days{cr::January / 1 / 1990}, 5s); test_transition(cr::sys_days{cr::January / 1 / 1991}, 6s); test_transition(cr::sys_days{cr::July / 1 / 1992}, 7s); test_transition(cr::sys_days{cr::July / 1 / 1993}, 8s); test_transition(cr::sys_days{cr::July / 1 / 1994}, 9s); test_transition(cr::sys_days{cr::January / 1 / 1996}, 10s); test_transition(cr::sys_days{cr::July / 1 / 1997}, 11s); test_transition(cr::sys_days{cr::January / 1 / 1999}, 12s); test_transition(cr::sys_days{cr::January / 1 / 2006}, 13s); test_transition(cr::sys_days{cr::January / 1 / 2009}, 14s); test_transition(cr::sys_days{cr::July / 1 / 2012}, 15s); test_transition(cr::sys_days{cr::July / 1 / 2015}, 16s); test_transition(cr::sys_days{cr::January / 1 / 2017}, 17s); } // Tests whether the return type is the expected type. static void test_return_type() { using namespace std::literals::chrono_literals; namespace cr = std::chrono; { [[maybe_unused]] std::same_as> decltype(auto) _ = cr::gps_clock::from_utc(cr::utc_time{0ns}); } { [[maybe_unused]] std::same_as> decltype(auto) _ = cr::gps_clock::from_utc(cr::utc_time{0us}); } { [[maybe_unused]] std::same_as> decltype(auto) _ = cr::gps_clock::from_utc(cr::utc_time{0ms}); } { [[maybe_unused]] std::same_as> decltype(auto) _ = cr::gps_clock::from_utc(cr::utc_time{cr::seconds{0}}); } { [[maybe_unused]] std::same_as> decltype(auto) _ = cr::gps_clock::from_utc(cr::utc_time{cr::minutes{0}}); } { [[maybe_unused]] std::same_as> decltype(auto) _ = cr::gps_clock::from_utc(cr::utc_time{cr::hours{0}}); } { [[maybe_unused]] std::same_as> decltype(auto) _ = cr::gps_clock::from_utc(cr::utc_time{cr::days{0}}); } { [[maybe_unused]] std::same_as> decltype(auto) _ = cr::gps_clock::from_utc(cr::utc_time{cr::weeks{0}}); } { [[maybe_unused]] std::same_as> decltype(auto) _ = cr::gps_clock::from_utc(cr::utc_time{cr::months{0}}); } { [[maybe_unused]] std::same_as> decltype(auto) _ = cr::gps_clock::from_utc(cr::utc_time{cr::years{0}}); } } int main(int, const char**) { using namespace std::literals::chrono_literals; std::chrono::utc_seconds time = std::chrono::utc_seconds{0s}; static_assert(noexcept(std::chrono::gps_clock::from_utc(time))); test_known_values(); test_transitions(); test_return_type(); return 0; }