Skip to content

Commit

Permalink
utc_clock::to_sys with floating point durations
Browse files Browse the repository at this point in the history
  • Loading branch information
MattStephanson committed Mar 1, 2021
1 parent 8a91f5a commit 40399b5
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 10 deletions.
18 changes: 14 additions & 4 deletions stl/inc/chrono
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#if _HAS_CXX20
#include <algorithm>
#include <atomic>
#include <cmath>
#include <compare>
#include <forward_list>
#include <memory>
Expand Down Expand Up @@ -2457,13 +2458,22 @@ namespace chrono {

template <class _Duration>
_NODISCARD static sys_time<common_type_t<_Duration, seconds>> to_sys(const utc_time<_Duration>& _Utc_time) {
using _CT = common_type_t<_Duration, seconds>;
const auto _Lsi{get_leap_second_info(_Utc_time)};
sys_time<common_type_t<_Duration, seconds>> _Sys_time{_Utc_time.time_since_epoch() - _Lsi.elapsed};
_CT _Ticks;
if (_Lsi.is_leap_second) {
constexpr auto _Delta{seconds{1} - common_type_t<_Duration, seconds>{1}};
_Sys_time = _CHRONO floor<seconds>(_Sys_time) + _Delta;
const auto _Leap_sec_minus_one = _CHRONO floor<seconds>(_Utc_time.time_since_epoch()) - _Lsi.elapsed;
if constexpr (is_integral_v<typename _Duration::rep>) {
constexpr auto _Delta{seconds{1} - _CT{1}};
_Ticks = _Leap_sec_minus_one + _Delta;
} else {
const auto _Leap_sec_begin = _CHRONO ceil<_CT>(_Leap_sec_minus_one + seconds{1});
_Ticks = _CT{_STD nextafter(_Leap_sec_begin.count(), typename _CT::rep{0})};
}
} else {
_Ticks = _Utc_time.time_since_epoch() - _Lsi.elapsed;
}
return _Sys_time;
return sys_time<_CT>{_Ticks};
}

template <class _Duration>
Expand Down
32 changes: 26 additions & 6 deletions tests/std/tests/P0355R7_calendars_and_time_zones_clocks/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include <cassert>
#include <chrono>
#include <cmath>
#include <compare>
#include <iterator>
#include <utility>
Expand Down Expand Up @@ -173,10 +174,11 @@ constexpr bool operator==(const leap_second_info& lhs, const leap_second_info& r
return lhs.is_leap_second == rhs.is_leap_second && lhs.elapsed == rhs.elapsed;
}

template <class DurationRep>
void test_leap_second_info(const leap_second& leap, seconds accum) {
const bool is_positive = (leap.value() == 1s);
// First UTC time when leap is counted, before insertion of a positive leap, after insertion of a negative one.
const utc_seconds utc_leap{leap.date().time_since_epoch() + accum + (is_positive ? 0s : -1s)};
const utc_time<duration<DurationRep>> utc_leap{leap.date().time_since_epoch() + accum + (is_positive ? 0s : -1s)};

auto lsi = get_leap_second_info(utc_leap - 1s);
assert(lsi == (leap_second_info{false, accum}));
Expand All @@ -197,11 +199,19 @@ void test_leap_second_info(const leap_second& leap, seconds accum) {

template <class Duration>
void test_utc_clock_to_sys(const leap_second& leap) {
auto u = utc_clock::from_sys(leap.date() - Duration{1}); // just before leap second
sys_time<Duration> before_leap;
if constexpr (is_integral_v<typename Duration::rep>) {
before_leap = leap.date() - Duration{1};
} else {
before_leap =
sys_time<Duration>{Duration{nextafter(leap.date().time_since_epoch().count(), typename Duration::rep{0})}};
}

auto u = utc_clock::from_sys(before_leap); // just before leap second
assert(utc_clock::from_sys(utc_clock::to_sys(u)) == u);
if (leap.value() == 1s) {
u += Duration{1};
assert(utc_clock::to_sys(u) == leap.date() - Duration{1}); // during
assert(utc_clock::to_sys(u) == before_leap); // during
} else {
assert(utc_clock::from_sys(utc_clock::to_sys(u)) == u);
}
Expand Down Expand Up @@ -342,11 +352,17 @@ void test_gps_tai_clocks_utc() {
int main() {
test_leap_second();

// This is the only time duration a leap second insertion that can be represented by a duration<float>.
assert(utc_clock::to_sys(utc_time<duration<float>>{duration<float>{78796800.0f}}).time_since_epoch().count()
== nextafter(78796800.0f, 0.0f));

seconds offset{0};
for (const auto& leap : get_tzdb().leap_seconds) {
test_leap_second_info(leap, offset);
test_leap_second_info<long long>(leap, offset);
test_leap_second_info<double>(leap, offset);
test_utc_clock_to_sys<seconds>(leap);
test_utc_clock_to_sys<milliseconds>(leap);
test_utc_clock_to_sys<duration<double>>(leap);
test_file_clock_from_utc<seconds>(leap);
test_file_clock_from_utc<milliseconds>(leap);
test_utc_clock_from_sys(leap, offset);
Expand All @@ -371,9 +387,11 @@ int main() {

offset = 0s;
for (const auto& leap : get_tzdb().leap_seconds) {
test_leap_second_info(leap, offset);
test_leap_second_info<long long>(leap, offset);
test_leap_second_info<double>(leap, offset);
test_utc_clock_to_sys<seconds>(leap);
test_utc_clock_to_sys<milliseconds>(leap);
test_utc_clock_to_sys<duration<double>>(leap);
test_file_clock_from_utc<seconds>(leap);
test_file_clock_from_utc<milliseconds>(leap);
test_utc_clock_from_sys(leap, offset);
Expand All @@ -396,9 +414,11 @@ int main() {

offset = 0s;
for (const auto& leap : get_tzdb().leap_seconds) {
test_leap_second_info(leap, offset);
test_leap_second_info<long long>(leap, offset);
test_leap_second_info<double>(leap, offset);
test_utc_clock_to_sys<seconds>(leap);
test_utc_clock_to_sys<milliseconds>(leap);
test_utc_clock_to_sys<duration<double>>(leap);
test_file_clock_from_utc<seconds>(leap);
test_file_clock_from_utc<milliseconds>(leap);
test_utc_clock_from_sys(leap, offset);
Expand Down

0 comments on commit 40399b5

Please sign in to comment.