File: to_sys.pass.cpp

package info (click to toggle)
llvm-toolchain-20 1%3A20.1.6-1~exp1
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 2,111,304 kB
  • sloc: cpp: 7,438,677; ansic: 1,393,822; asm: 1,012,926; python: 241,650; f90: 86,635; objc: 75,479; lisp: 42,144; pascal: 17,286; sh: 10,027; ml: 5,082; perl: 4,730; awk: 3,523; makefile: 3,349; javascript: 2,251; xml: 892; fortran: 672
file content (252 lines) | stat: -rw-r--r-- 12,016 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
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;
}