]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/test/test-time-util.c
core/scope: drop effectively unused unit_watch_pidref() calls (#38186)
[thirdparty/systemd.git] / src / test / test-time-util.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
cb0dac05 2
fa34123c 3#include <stdlib.h>
4d5ad9d9 4#include "env-util.h"
1bb4b028 5#include "random-util.h"
d68c645b 6#include "serialize.h"
1bb4b028 7#include "string-util.h"
6accc7a2 8#include "strv.h"
f0e2e0db 9#include "tests.h"
cf0fbc49 10#include "time-util.h"
cb0dac05 11
8b51c41f
YW
12#define TRIAL 100u
13
4f7452a8 14TEST(parse_sec) {
cb0dac05
LP
15 usec_t u;
16
17 assert_se(parse_sec("5s", &u) >= 0);
18 assert_se(u == 5 * USEC_PER_SEC);
19 assert_se(parse_sec("5s500ms", &u) >= 0);
20 assert_se(u == 5 * USEC_PER_SEC + 500 * USEC_PER_MSEC);
21 assert_se(parse_sec(" 5s 500ms ", &u) >= 0);
22 assert_se(u == 5 * USEC_PER_SEC + 500 * USEC_PER_MSEC);
23 assert_se(parse_sec(" 5.5s ", &u) >= 0);
24 assert_se(u == 5 * USEC_PER_SEC + 500 * USEC_PER_MSEC);
25 assert_se(parse_sec(" 5.5s 0.5ms ", &u) >= 0);
26 assert_se(u == 5 * USEC_PER_SEC + 500 * USEC_PER_MSEC + 500);
27 assert_se(parse_sec(" .22s ", &u) >= 0);
28 assert_se(u == 220 * USEC_PER_MSEC);
29 assert_se(parse_sec(" .50y ", &u) >= 0);
30 assert_se(u == USEC_PER_YEAR / 2);
31 assert_se(parse_sec("2.5", &u) >= 0);
32 assert_se(u == 2500 * USEC_PER_MSEC);
33 assert_se(parse_sec(".7", &u) >= 0);
34 assert_se(u == 700 * USEC_PER_MSEC);
5efdbf11
LP
35 assert_se(parse_sec("23us", &u) >= 0);
36 assert_se(u == 23);
d0a6d7c4
LP
37 assert_se(parse_sec("23μs", &u) >= 0); /* greek small letter mu */
38 assert_se(u == 23);
39 assert_se(parse_sec("23µs", &u) >= 0); /* micro symbol */
5efdbf11 40 assert_se(u == 23);
b1d6dcf5
ZJS
41 assert_se(parse_sec("infinity", &u) >= 0);
42 assert_se(u == USEC_INFINITY);
43 assert_se(parse_sec(" infinity ", &u) >= 0);
44 assert_se(u == USEC_INFINITY);
279f52a1
FB
45 assert_se(parse_sec("+3.1s", &u) >= 0);
46 assert_se(u == 3100 * USEC_PER_MSEC);
ed2e7967
YW
47 assert_se(parse_sec("3.1s.2", &u) >= 0);
48 assert_se(u == 3300 * USEC_PER_MSEC);
49 assert_se(parse_sec("3.1 .2", &u) >= 0);
50 assert_se(u == 3300 * USEC_PER_MSEC);
51 assert_se(parse_sec("3.1 sec .2 sec", &u) >= 0);
52 assert_se(u == 3300 * USEC_PER_MSEC);
53 assert_se(parse_sec("3.1 sec 1.2 sec", &u) >= 0);
54 assert_se(u == 4300 * USEC_PER_MSEC);
cb0dac05
LP
55
56 assert_se(parse_sec(" xyz ", &u) < 0);
57 assert_se(parse_sec("", &u) < 0);
58 assert_se(parse_sec(" . ", &u) < 0);
59 assert_se(parse_sec(" 5. ", &u) < 0);
60 assert_se(parse_sec(".s ", &u) < 0);
5a9fb358
LP
61 assert_se(parse_sec("-5s ", &u) < 0);
62 assert_se(parse_sec("-0.3s ", &u) < 0);
63 assert_se(parse_sec("-0.0s ", &u) < 0);
64 assert_se(parse_sec("-0.-0s ", &u) < 0);
65 assert_se(parse_sec("0.-0s ", &u) < 0);
66 assert_se(parse_sec("3.-0s ", &u) < 0);
b1d6dcf5
ZJS
67 assert_se(parse_sec(" infinity .7", &u) < 0);
68 assert_se(parse_sec(".3 infinity", &u) < 0);
279f52a1
FB
69 assert_se(parse_sec("3.+1s", &u) < 0);
70 assert_se(parse_sec("3. 1s", &u) < 0);
71 assert_se(parse_sec("3.s", &u) < 0);
ed2e7967
YW
72 assert_se(parse_sec("12.34.56", &u) < 0);
73 assert_se(parse_sec("12..34", &u) < 0);
74 assert_se(parse_sec("..1234", &u) < 0);
75 assert_se(parse_sec("1234..", &u) < 0);
cb0dac05
LP
76}
77
4f7452a8 78TEST(parse_sec_fix_0) {
0004f698
ZJS
79 usec_t u;
80
81 assert_se(parse_sec_fix_0("5s", &u) >= 0);
82 assert_se(u == 5 * USEC_PER_SEC);
83 assert_se(parse_sec_fix_0("0s", &u) >= 0);
def34f63 84 assert_se(u == USEC_INFINITY);
0004f698
ZJS
85 assert_se(parse_sec_fix_0("0", &u) >= 0);
86 assert_se(u == USEC_INFINITY);
87 assert_se(parse_sec_fix_0(" 0", &u) >= 0);
88 assert_se(u == USEC_INFINITY);
89}
90
4f7452a8 91TEST(parse_sec_def_infinity) {
7b61ce3c
FB
92 usec_t u;
93
7b61ce3c
FB
94 assert_se(parse_sec_def_infinity("5s", &u) >= 0);
95 assert_se(u == 5 * USEC_PER_SEC);
96 assert_se(parse_sec_def_infinity("", &u) >= 0);
97 assert_se(u == USEC_INFINITY);
98 assert_se(parse_sec_def_infinity(" ", &u) >= 0);
99 assert_se(u == USEC_INFINITY);
100 assert_se(parse_sec_def_infinity("0s", &u) >= 0);
101 assert_se(u == 0);
102 assert_se(parse_sec_def_infinity("0", &u) >= 0);
103 assert_se(u == 0);
104 assert_se(parse_sec_def_infinity(" 0", &u) >= 0);
105 assert_se(u == 0);
106 assert_se(parse_sec_def_infinity("-5s", &u) < 0);
107}
108
4f7452a8 109TEST(parse_time) {
519cffec
LP
110 usec_t u;
111
112 assert_se(parse_time("5", &u, 1) >= 0);
113 assert_se(u == 5);
114
115 assert_se(parse_time("5", &u, USEC_PER_MSEC) >= 0);
116 assert_se(u == 5 * USEC_PER_MSEC);
117
118 assert_se(parse_time("5", &u, USEC_PER_SEC) >= 0);
119 assert_se(u == 5 * USEC_PER_SEC);
120
121 assert_se(parse_time("5s", &u, 1) >= 0);
122 assert_se(u == 5 * USEC_PER_SEC);
123
124 assert_se(parse_time("5s", &u, USEC_PER_SEC) >= 0);
125 assert_se(u == 5 * USEC_PER_SEC);
126
127 assert_se(parse_time("5s", &u, USEC_PER_MSEC) >= 0);
128 assert_se(u == 5 * USEC_PER_SEC);
db4e6107
YW
129
130 assert_se(parse_time("11111111111111y", &u, 1) == -ERANGE);
ed2e7967 131 assert_se(parse_time("1.1111111111111y", &u, 1) >= 0);
519cffec
LP
132}
133
4f7452a8 134TEST(parse_nsec) {
cb0dac05
LP
135 nsec_t u;
136
137 assert_se(parse_nsec("5s", &u) >= 0);
138 assert_se(u == 5 * NSEC_PER_SEC);
139 assert_se(parse_nsec("5s500ms", &u) >= 0);
140 assert_se(u == 5 * NSEC_PER_SEC + 500 * NSEC_PER_MSEC);
141 assert_se(parse_nsec(" 5s 500ms ", &u) >= 0);
142 assert_se(u == 5 * NSEC_PER_SEC + 500 * NSEC_PER_MSEC);
143 assert_se(parse_nsec(" 5.5s ", &u) >= 0);
144 assert_se(u == 5 * NSEC_PER_SEC + 500 * NSEC_PER_MSEC);
145 assert_se(parse_nsec(" 5.5s 0.5ms ", &u) >= 0);
146 assert_se(u == 5 * NSEC_PER_SEC + 500 * NSEC_PER_MSEC + 500 * NSEC_PER_USEC);
147 assert_se(parse_nsec(" .22s ", &u) >= 0);
148 assert_se(u == 220 * NSEC_PER_MSEC);
149 assert_se(parse_nsec(" .50y ", &u) >= 0);
150 assert_se(u == NSEC_PER_YEAR / 2);
151 assert_se(parse_nsec("2.5", &u) >= 0);
152 assert_se(u == 2);
153 assert_se(parse_nsec(".7", &u) >= 0);
154 assert_se(u == 0);
fdd30a15
DM
155 assert_se(parse_nsec("infinity", &u) >= 0);
156 assert_se(u == NSEC_INFINITY);
157 assert_se(parse_nsec(" infinity ", &u) >= 0);
158 assert_se(u == NSEC_INFINITY);
279f52a1
FB
159 assert_se(parse_nsec("+3.1s", &u) >= 0);
160 assert_se(u == 3100 * NSEC_PER_MSEC);
ed2e7967
YW
161 assert_se(parse_nsec("3.1s.2", &u) >= 0);
162 assert_se(u == 3100 * NSEC_PER_MSEC);
163 assert_se(parse_nsec("3.1 .2s", &u) >= 0);
164 assert_se(u == 200 * NSEC_PER_MSEC + 3);
165 assert_se(parse_nsec("3.1 sec .2 sec", &u) >= 0);
166 assert_se(u == 3300 * NSEC_PER_MSEC);
167 assert_se(parse_nsec("3.1 sec 1.2 sec", &u) >= 0);
168 assert_se(u == 4300 * NSEC_PER_MSEC);
cb0dac05
LP
169
170 assert_se(parse_nsec(" xyz ", &u) < 0);
171 assert_se(parse_nsec("", &u) < 0);
172 assert_se(parse_nsec(" . ", &u) < 0);
173 assert_se(parse_nsec(" 5. ", &u) < 0);
174 assert_se(parse_nsec(".s ", &u) < 0);
fdd30a15
DM
175 assert_se(parse_nsec(" infinity .7", &u) < 0);
176 assert_se(parse_nsec(".3 infinity", &u) < 0);
279f52a1
FB
177 assert_se(parse_nsec("-5s ", &u) < 0);
178 assert_se(parse_nsec("-0.3s ", &u) < 0);
179 assert_se(parse_nsec("-0.0s ", &u) < 0);
180 assert_se(parse_nsec("-0.-0s ", &u) < 0);
181 assert_se(parse_nsec("0.-0s ", &u) < 0);
182 assert_se(parse_nsec("3.-0s ", &u) < 0);
183 assert_se(parse_nsec(" infinity .7", &u) < 0);
184 assert_se(parse_nsec(".3 infinity", &u) < 0);
185 assert_se(parse_nsec("3.+1s", &u) < 0);
186 assert_se(parse_nsec("3. 1s", &u) < 0);
187 assert_se(parse_nsec("3.s", &u) < 0);
ed2e7967
YW
188 assert_se(parse_nsec("12.34.56", &u) < 0);
189 assert_se(parse_nsec("12..34", &u) < 0);
190 assert_se(parse_nsec("..1234", &u) < 0);
191 assert_se(parse_nsec("1234..", &u) < 0);
db4e6107 192 assert_se(parse_nsec("1111111111111y", &u) == -ERANGE);
ed2e7967 193 assert_se(parse_nsec("1.111111111111y", &u) >= 0);
cb0dac05
LP
194}
195
2fa4092c 196static void test_format_timespan_one(usec_t x, usec_t accuracy) {
2fa4092c 197 char l[FORMAT_TIMESPAN_MAX];
4d9685be 198 const char *t;
2fa4092c
LP
199 usec_t y;
200
41bc83ed 201 log_debug(USEC_FMT" (at accuracy "USEC_FMT")", x, accuracy);
2fa4092c 202
4d9685be 203 assert_se(t = format_timespan(l, sizeof l, x, accuracy));
41bc83ed 204 log_debug(" = <%s>", t);
2fa4092c 205
4d9685be 206 assert_se(parse_sec(t, &y) >= 0);
41bc83ed 207 log_debug(" = "USEC_FMT, y);
2fa4092c
LP
208
209 if (accuracy <= 0)
210 accuracy = 1;
211
212 assert_se(x / accuracy == y / accuracy);
213}
214
4f7452a8 215static void test_format_timespan_accuracy(usec_t accuracy) {
f1880a4b
ZJS
216 log_info("/* %s accuracy="USEC_FMT" */", __func__, accuracy);
217
2fa4092c
LP
218 test_format_timespan_one(0, accuracy);
219 test_format_timespan_one(1, accuracy);
220 test_format_timespan_one(1*USEC_PER_SEC, accuracy);
221 test_format_timespan_one(999*USEC_PER_MSEC, accuracy);
222 test_format_timespan_one(1234567, accuracy);
223 test_format_timespan_one(12, accuracy);
224 test_format_timespan_one(123, accuracy);
225 test_format_timespan_one(1234, accuracy);
226 test_format_timespan_one(12345, accuracy);
227 test_format_timespan_one(123456, accuracy);
228 test_format_timespan_one(1234567, accuracy);
229 test_format_timespan_one(12345678, accuracy);
230 test_format_timespan_one(1200000, accuracy);
231 test_format_timespan_one(1230000, accuracy);
2fa4092c
LP
232 test_format_timespan_one(1234000, accuracy);
233 test_format_timespan_one(1234500, accuracy);
234 test_format_timespan_one(1234560, accuracy);
235 test_format_timespan_one(1234567, accuracy);
236 test_format_timespan_one(986087, accuracy);
237 test_format_timespan_one(500 * USEC_PER_MSEC, accuracy);
238 test_format_timespan_one(9*USEC_PER_YEAR/5 - 23, accuracy);
b1d6dcf5 239 test_format_timespan_one(USEC_INFINITY, accuracy);
2fa4092c
LP
240}
241
4f7452a8
JJ
242TEST(format_timespan) {
243 test_format_timespan_accuracy(1);
244 test_format_timespan_accuracy(USEC_PER_MSEC);
245 test_format_timespan_accuracy(USEC_PER_SEC);
9102c625
YW
246
247 /* See issue #23928. */
3d41b6b8 248 _cleanup_free_ char *buf = NULL;
9102c625
YW
249 assert_se(buf = new(char, 5));
250 assert_se(buf == format_timespan(buf, 5, 100005, 1000));
4f7452a8 251}
bdaeafea 252
4f7452a8 253TEST(verify_timezone) {
bdaeafea
ZJS
254 assert_se(verify_timezone("Europe/Berlin", LOG_DEBUG) == 0);
255 assert_se(verify_timezone("Australia/Sydney", LOG_DEBUG) == 0);
256 assert_se(verify_timezone("Europe/Do not exist", LOG_DEBUG) == -EINVAL);
257 assert_se(verify_timezone("Europe/DoNotExist", LOG_DEBUG) == -ENOENT);
258 assert_se(verify_timezone("/DoNotExist", LOG_DEBUG) == -EINVAL);
259 assert_se(verify_timezone("DoNotExist/", LOG_DEBUG) == -EINVAL);
260}
261
4f7452a8 262TEST(timezone_is_valid) {
089fb865
MG
263 assert_se(timezone_is_valid("Europe/Berlin", LOG_ERR));
264 assert_se(timezone_is_valid("Australia/Sydney", LOG_ERR));
265 assert_se(!timezone_is_valid("Europe/Do not exist", LOG_ERR));
6accc7a2
RC
266}
267
4f7452a8 268TEST(get_timezones) {
6accc7a2
RC
269 _cleanup_strv_free_ char **zones = NULL;
270 int r;
6accc7a2
RC
271
272 r = get_timezones(&zones);
273 assert_se(r == 0);
274
f0e2e0db 275 STRV_FOREACH(zone, zones) {
dc9849b1
ZJS
276 r = verify_timezone(*zone, LOG_ERR);
277 log_debug_errno(r, "verify_timezone(\"%s\"): %m", *zone);
278 assert_se(r >= 0 || r == -ENOENT);
f0e2e0db 279 }
53f555b6
LP
280}
281
4f7452a8 282TEST(usec_add) {
53f555b6
LP
283 assert_se(usec_add(0, 0) == 0);
284 assert_se(usec_add(1, 4) == 5);
285 assert_se(usec_add(USEC_INFINITY, 5) == USEC_INFINITY);
286 assert_se(usec_add(5, USEC_INFINITY) == USEC_INFINITY);
287 assert_se(usec_add(USEC_INFINITY-5, 2) == USEC_INFINITY-3);
288 assert_se(usec_add(USEC_INFINITY-2, 2) == USEC_INFINITY);
289 assert_se(usec_add(USEC_INFINITY-1, 2) == USEC_INFINITY);
290 assert_se(usec_add(USEC_INFINITY, 2) == USEC_INFINITY);
6accc7a2
RC
291}
292
4f7452a8 293TEST(usec_sub_unsigned) {
54d8ef14
LP
294 assert_se(usec_sub_unsigned(0, 0) == 0);
295 assert_se(usec_sub_unsigned(0, 2) == 0);
296 assert_se(usec_sub_unsigned(0, USEC_INFINITY) == 0);
297 assert_se(usec_sub_unsigned(1, 0) == 1);
298 assert_se(usec_sub_unsigned(1, 1) == 0);
299 assert_se(usec_sub_unsigned(1, 2) == 0);
300 assert_se(usec_sub_unsigned(1, 3) == 0);
301 assert_se(usec_sub_unsigned(1, USEC_INFINITY) == 0);
302 assert_se(usec_sub_unsigned(USEC_INFINITY-1, 0) == USEC_INFINITY-1);
303 assert_se(usec_sub_unsigned(USEC_INFINITY-1, 1) == USEC_INFINITY-2);
304 assert_se(usec_sub_unsigned(USEC_INFINITY-1, 2) == USEC_INFINITY-3);
305 assert_se(usec_sub_unsigned(USEC_INFINITY-1, USEC_INFINITY-2) == 1);
306 assert_se(usec_sub_unsigned(USEC_INFINITY-1, USEC_INFINITY-1) == 0);
307 assert_se(usec_sub_unsigned(USEC_INFINITY-1, USEC_INFINITY) == 0);
308 assert_se(usec_sub_unsigned(USEC_INFINITY, 0) == USEC_INFINITY);
309 assert_se(usec_sub_unsigned(USEC_INFINITY, 1) == USEC_INFINITY);
310 assert_se(usec_sub_unsigned(USEC_INFINITY, 2) == USEC_INFINITY);
311 assert_se(usec_sub_unsigned(USEC_INFINITY, USEC_INFINITY) == USEC_INFINITY);
312}
313
4f7452a8 314TEST(usec_sub_signed) {
54d8ef14
LP
315 assert_se(usec_sub_signed(0, 0) == 0);
316 assert_se(usec_sub_signed(4, 1) == 3);
317 assert_se(usec_sub_signed(4, 4) == 0);
318 assert_se(usec_sub_signed(4, 5) == 0);
782c6e5c 319
54d8ef14 320 assert_se(usec_sub_signed(USEC_INFINITY-3, -3) == USEC_INFINITY);
54d8ef14
LP
321 assert_se(usec_sub_signed(USEC_INFINITY-3, -4) == USEC_INFINITY);
322 assert_se(usec_sub_signed(USEC_INFINITY-3, -5) == USEC_INFINITY);
323 assert_se(usec_sub_signed(USEC_INFINITY, 5) == USEC_INFINITY);
782c6e5c
LP
324
325 assert_se(usec_sub_signed(0, INT64_MAX) == 0);
326 assert_se(usec_sub_signed(0, -INT64_MAX) == INT64_MAX);
327 assert_se(usec_sub_signed(0, INT64_MIN) == (usec_t) INT64_MAX + 1);
328 assert_se(usec_sub_signed(0, -(INT64_MIN+1)) == 0);
329
330 assert_se(usec_sub_signed(USEC_INFINITY, INT64_MAX) == USEC_INFINITY);
331 assert_se(usec_sub_signed(USEC_INFINITY, -INT64_MAX) == USEC_INFINITY);
332 assert_se(usec_sub_signed(USEC_INFINITY, INT64_MIN) == USEC_INFINITY);
333 assert_se(usec_sub_signed(USEC_INFINITY, -(INT64_MIN+1)) == USEC_INFINITY);
334
335 assert_se(usec_sub_signed(USEC_INFINITY-1, INT64_MAX) == USEC_INFINITY-1-INT64_MAX);
336 assert_se(usec_sub_signed(USEC_INFINITY-1, -INT64_MAX) == USEC_INFINITY);
337 assert_se(usec_sub_signed(USEC_INFINITY-1, INT64_MIN) == USEC_INFINITY);
338 assert_se(usec_sub_signed(USEC_INFINITY-1, -(INT64_MIN+1)) == USEC_INFINITY-1-((usec_t) (-(INT64_MIN+1))));
04a1d84c
LP
339}
340
4f7452a8 341TEST(format_timestamp) {
8b51c41f 342 for (unsigned i = 0; i < TRIAL; i++) {
89eb3d7c 343 char buf[CONST_MAX(FORMAT_TIMESTAMP_MAX, FORMAT_TIMESPAN_MAX)];
21b3a0fc
LP
344 usec_t x, y;
345
8b51c41f 346 x = random_u64_range(USEC_TIMESTAMP_FORMATTABLE_MAX - USEC_PER_SEC) + USEC_PER_SEC;
21b3a0fc
LP
347
348 assert_se(format_timestamp(buf, sizeof(buf), x));
41bc83ed 349 log_debug("%s", buf);
21b3a0fc
LP
350 assert_se(parse_timestamp(buf, &y) >= 0);
351 assert_se(x / USEC_PER_SEC == y / USEC_PER_SEC);
352
ed4a5b43
FS
353 assert_se(format_timestamp_style(buf, sizeof(buf), x, TIMESTAMP_UNIX));
354 log_debug("%s", buf);
355 assert_se(parse_timestamp(buf, &y) >= 0);
356 assert_se(x / USEC_PER_SEC == y / USEC_PER_SEC);
357
7b3eb5c9 358 assert_se(format_timestamp_style(buf, sizeof(buf), x, TIMESTAMP_UTC));
41bc83ed 359 log_debug("%s", buf);
21b3a0fc
LP
360 assert_se(parse_timestamp(buf, &y) >= 0);
361 assert_se(x / USEC_PER_SEC == y / USEC_PER_SEC);
362
7b3eb5c9 363 assert_se(format_timestamp_style(buf, sizeof(buf), x, TIMESTAMP_US));
41bc83ed 364 log_debug("%s", buf);
21b3a0fc
LP
365 assert_se(parse_timestamp(buf, &y) >= 0);
366 assert_se(x == y);
367
7b3eb5c9 368 assert_se(format_timestamp_style(buf, sizeof(buf), x, TIMESTAMP_US_UTC));
41bc83ed 369 log_debug("%s", buf);
21b3a0fc
LP
370 assert_se(parse_timestamp(buf, &y) >= 0);
371 assert_se(x == y);
372
ff6db56a
YW
373 if (x > 2 * USEC_PER_DAY) {
374 assert_se(format_timestamp_style(buf, sizeof(buf), x, TIMESTAMP_DATE));
375 log_debug("%s", buf);
376 assert_se(parse_timestamp(buf, &y) >= 0);
377 assert_se(y > usec_sub_unsigned(x, 2 * USEC_PER_DAY) && y < usec_add(x, 2 * USEC_PER_DAY));
378 }
64f3419e 379
21b3a0fc 380 assert_se(format_timestamp_relative(buf, sizeof(buf), x));
41bc83ed 381 log_debug("%s", buf);
21b3a0fc
LP
382 assert_se(parse_timestamp(buf, &y) >= 0);
383
384 /* The two calls above will run with a slightly different local time. Make sure we are in the same
385 * range however, but give enough leeway that this is unlikely to explode. And of course,
386 * format_timestamp_relative() scales the accuracy with the distance from the current time up to one
387 * month, cover for that too. */
388 assert_se(y > x ? y - x : x - y <= USEC_PER_MONTH + USEC_PER_DAY);
389 }
390}
391
8b51c41f 392static void test_format_timestamp_impl(usec_t x) {
78b95cca 393 bool success, override;
8b51c41f 394 const char *xx, *yy;
3f1d4999 395 usec_t y, x_sec, y_sec;
8b51c41f
YW
396
397 xx = FORMAT_TIMESTAMP(x);
3f1d4999
YW
398 ASSERT_NOT_NULL(xx);
399 ASSERT_OK(parse_timestamp(xx, &y));
8b51c41f 400 yy = FORMAT_TIMESTAMP(y);
3f1d4999 401 ASSERT_NOT_NULL(yy);
8b51c41f 402
3f1d4999
YW
403 x_sec = x / USEC_PER_SEC;
404 y_sec = y / USEC_PER_SEC;
405 success = (x_sec == y_sec) && streq(xx, yy);
3cf362f6
ZJS
406 /* Workaround for https://github.com/systemd/systemd/issues/28472
407 * and https://github.com/systemd/systemd/pull/35471. */
78b95cca 408 override = !success &&
3cf362f6
ZJS
409 (STRPTR_IN_SET(tzname[0], "CAT", "EAT", "WET") ||
410 STRPTR_IN_SET(tzname[1], "CAT", "EAT", "WET")) &&
3f1d4999 411 (x_sec > y_sec ? x_sec - y_sec : y_sec - x_sec) == 3600; /* 1 hour, ignore fractional second */
78b95cca
ZJS
412 log_full(success ? LOG_DEBUG : override ? LOG_WARNING : LOG_ERR,
413 "@" USEC_FMT " → %s → @" USEC_FMT " → %s%s",
414 x, xx, y, yy,
415 override ? ", ignoring." : "");
416 if (!override) {
3f1d4999
YW
417 if (!success)
418 log_warning("tzname[0]=\"%s\", tzname[1]=\"%s\"", tzname[0], tzname[1]);
419 ASSERT_EQ(x_sec, y_sec);
c79e88b3 420 ASSERT_STREQ(xx, yy);
78b95cca 421 }
8b51c41f
YW
422}
423
424static void test_format_timestamp_loop(void) {
3cf362f6 425 test_format_timestamp_impl(USEC_PER_DAY + USEC_PER_SEC);
6bed3742
YW
426 test_format_timestamp_impl(USEC_TIMESTAMP_FORMATTABLE_MAX_32BIT-1);
427 test_format_timestamp_impl(USEC_TIMESTAMP_FORMATTABLE_MAX_32BIT);
428 test_format_timestamp_impl(USEC_TIMESTAMP_FORMATTABLE_MAX-1);
429 test_format_timestamp_impl(USEC_TIMESTAMP_FORMATTABLE_MAX);
8b51c41f 430
78b95cca
ZJS
431 /* Two cases which trigger https://github.com/systemd/systemd/issues/28472 */
432 test_format_timestamp_impl(1504938962980066);
433 test_format_timestamp_impl(1509482094632752);
434
8b51c41f
YW
435 for (unsigned i = 0; i < TRIAL; i++) {
436 usec_t x;
437
438 x = random_u64_range(USEC_TIMESTAMP_FORMATTABLE_MAX - USEC_PER_SEC) + USEC_PER_SEC;
439 test_format_timestamp_impl(x);
440 }
441}
442
4f7452a8 443TEST(FORMAT_TIMESTAMP) {
8b51c41f
YW
444 test_format_timestamp_loop();
445}
ae7c644c 446
0b20d70d
YW
447static void test_format_timestamp_with_tz_one(const char *tz) {
448 const char *saved_tz, *colon_tz;
ae7c644c 449
0b20d70d 450 if (!timezone_is_valid(tz, LOG_DEBUG))
8b51c41f
YW
451 return;
452
0b20d70d 453 log_info("/* %s(%s) */", __func__, tz);
8b51c41f
YW
454
455 saved_tz = getenv("TZ");
456
0b20d70d
YW
457 assert_se(colon_tz = strjoina(":", tz));
458 assert_se(setenv("TZ", colon_tz, 1) >= 0);
8b51c41f
YW
459 tzset();
460 log_debug("%s: tzname[0]=%s, tzname[1]=%s", tz, strempty(tzname[0]), strempty(tzname[1]));
461
462 test_format_timestamp_loop();
463
464 assert_se(set_unset_env("TZ", saved_tz, true) == 0);
465 tzset();
466}
467
468TEST(FORMAT_TIMESTAMP_with_tz) {
0b20d70d
YW
469 _cleanup_strv_free_ char **timezones = NULL;
470
e3201a69
FS
471 test_format_timestamp_with_tz_one("UTC");
472
473 if (!slow_tests_enabled())
474 return (void) log_tests_skipped("slow tests are disabled");
475
0b20d70d
YW
476 assert_se(get_timezones(&timezones) >= 0);
477 STRV_FOREACH(tz, timezones)
478 test_format_timestamp_with_tz_one(*tz);
ae7c644c
ZJS
479}
480
d5e6f36c
ZJS
481TEST(format_timestamp_relative_full) {
482 char buf[CONST_MAX(FORMAT_TIMESTAMP_MAX, FORMAT_TIMESPAN_MAX)];
483 usec_t x;
484
485 /* Years and months */
486 x = now(CLOCK_REALTIME) - (1*USEC_PER_YEAR + 1*USEC_PER_MONTH);
d65c289f 487 assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_REALTIME, true));
d5e6f36c 488 log_debug("%s", buf);
c79e88b3 489 ASSERT_STREQ(buf, "1 year 1 month ago");
d5e6f36c 490
d65c289f
MY
491 x = now(CLOCK_MONOTONIC) + (1*USEC_PER_YEAR + 1.5*USEC_PER_MONTH);
492 assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_MONOTONIC, false));
493 log_debug("%s", buf);
c79e88b3 494 ASSERT_STREQ(buf, "1 year 1 month left");
d65c289f 495
d5e6f36c 496 x = now(CLOCK_REALTIME) - (1*USEC_PER_YEAR + 2*USEC_PER_MONTH);
d65c289f 497 assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_REALTIME, true));
d5e6f36c 498 log_debug("%s", buf);
c79e88b3 499 ASSERT_STREQ(buf, "1 year 2 months ago");
d5e6f36c
ZJS
500
501 x = now(CLOCK_REALTIME) - (2*USEC_PER_YEAR + 1*USEC_PER_MONTH);
d65c289f 502 assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_REALTIME, true));
d5e6f36c 503 log_debug("%s", buf);
c79e88b3 504 ASSERT_STREQ(buf, "2 years 1 month ago");
d5e6f36c
ZJS
505
506 x = now(CLOCK_REALTIME) - (2*USEC_PER_YEAR + 2*USEC_PER_MONTH);
d65c289f 507 assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_REALTIME, true));
d5e6f36c 508 log_debug("%s", buf);
c79e88b3 509 ASSERT_STREQ(buf, "2 years 2 months ago");
d5e6f36c
ZJS
510
511 /* Months and days */
512 x = now(CLOCK_REALTIME) - (1*USEC_PER_MONTH + 1*USEC_PER_DAY);
d65c289f 513 assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_REALTIME, true));
d5e6f36c 514 log_debug("%s", buf);
c79e88b3 515 ASSERT_STREQ(buf, "1 month 1 day ago");
d5e6f36c
ZJS
516
517 x = now(CLOCK_REALTIME) - (1*USEC_PER_MONTH + 2*USEC_PER_DAY);
d65c289f 518 assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_REALTIME, true));
d5e6f36c 519 log_debug("%s", buf);
c79e88b3 520 ASSERT_STREQ(buf, "1 month 2 days ago");
d5e6f36c
ZJS
521
522 x = now(CLOCK_REALTIME) - (2*USEC_PER_MONTH + 1*USEC_PER_DAY);
d65c289f 523 assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_REALTIME, true));
d5e6f36c 524 log_debug("%s", buf);
c79e88b3 525 ASSERT_STREQ(buf, "2 months 1 day ago");
d5e6f36c
ZJS
526
527 x = now(CLOCK_REALTIME) - (2*USEC_PER_MONTH + 2*USEC_PER_DAY);
d65c289f 528 assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_REALTIME, true));
d5e6f36c 529 log_debug("%s", buf);
c79e88b3 530 ASSERT_STREQ(buf, "2 months 2 days ago");
d5e6f36c
ZJS
531
532 /* Weeks and days */
533 x = now(CLOCK_REALTIME) - (1*USEC_PER_WEEK + 1*USEC_PER_DAY);
d65c289f 534 assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_REALTIME, true));
d5e6f36c 535 log_debug("%s", buf);
c79e88b3 536 ASSERT_STREQ(buf, "1 week 1 day ago");
d5e6f36c
ZJS
537
538 x = now(CLOCK_REALTIME) - (1*USEC_PER_WEEK + 2*USEC_PER_DAY);
d65c289f 539 assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_REALTIME, true));
d5e6f36c 540 log_debug("%s", buf);
c79e88b3 541 ASSERT_STREQ(buf, "1 week 2 days ago");
d5e6f36c
ZJS
542
543 x = now(CLOCK_REALTIME) - (2*USEC_PER_WEEK + 1*USEC_PER_DAY);
d65c289f 544 assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_REALTIME, true));
d5e6f36c 545 log_debug("%s", buf);
c79e88b3 546 ASSERT_STREQ(buf, "2 weeks 1 day ago");
d5e6f36c
ZJS
547
548 x = now(CLOCK_REALTIME) - (2*USEC_PER_WEEK + 2*USEC_PER_DAY);
d65c289f 549 assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_REALTIME, true));
d5e6f36c 550 log_debug("%s", buf);
c79e88b3 551 ASSERT_STREQ(buf, "2 weeks 2 days ago");
d5e6f36c
ZJS
552}
553
4f7452a8 554TEST(format_timestamp_relative) {
89eb3d7c 555 char buf[CONST_MAX(FORMAT_TIMESTAMP_MAX, FORMAT_TIMESPAN_MAX)];
45eb4d22
AW
556 usec_t x;
557
558 /* Only testing timestamps in the past so we don't need to add some delta to account for time passing
559 * by while we are running the tests (unless we're running on potatoes and 24 hours somehow passes
560 * between our call to now() and format_timestamp_relative's call to now()). */
561
562 /* Years and months */
563 x = now(CLOCK_REALTIME) - (1*USEC_PER_YEAR + 1*USEC_PER_MONTH);
564 assert_se(format_timestamp_relative(buf, sizeof(buf), x));
41bc83ed 565 log_debug("%s", buf);
c79e88b3 566 ASSERT_STREQ(buf, "1 year 1 month ago");
45eb4d22
AW
567
568 x = now(CLOCK_REALTIME) - (1*USEC_PER_YEAR + 2*USEC_PER_MONTH);
569 assert_se(format_timestamp_relative(buf, sizeof(buf), x));
41bc83ed 570 log_debug("%s", buf);
c79e88b3 571 ASSERT_STREQ(buf, "1 year 2 months ago");
45eb4d22
AW
572
573 x = now(CLOCK_REALTIME) - (2*USEC_PER_YEAR + 1*USEC_PER_MONTH);
574 assert_se(format_timestamp_relative(buf, sizeof(buf), x));
41bc83ed 575 log_debug("%s", buf);
c79e88b3 576 ASSERT_STREQ(buf, "2 years 1 month ago");
45eb4d22
AW
577
578 x = now(CLOCK_REALTIME) - (2*USEC_PER_YEAR + 2*USEC_PER_MONTH);
579 assert_se(format_timestamp_relative(buf, sizeof(buf), x));
41bc83ed 580 log_debug("%s", buf);
c79e88b3 581 ASSERT_STREQ(buf, "2 years 2 months ago");
45eb4d22
AW
582
583 /* Months and days */
584 x = now(CLOCK_REALTIME) - (1*USEC_PER_MONTH + 1*USEC_PER_DAY);
585 assert_se(format_timestamp_relative(buf, sizeof(buf), x));
41bc83ed 586 log_debug("%s", buf);
c79e88b3 587 ASSERT_STREQ(buf, "1 month 1 day ago");
45eb4d22
AW
588
589 x = now(CLOCK_REALTIME) - (1*USEC_PER_MONTH + 2*USEC_PER_DAY);
590 assert_se(format_timestamp_relative(buf, sizeof(buf), x));
41bc83ed 591 log_debug("%s", buf);
c79e88b3 592 ASSERT_STREQ(buf, "1 month 2 days ago");
45eb4d22
AW
593
594 x = now(CLOCK_REALTIME) - (2*USEC_PER_MONTH + 1*USEC_PER_DAY);
595 assert_se(format_timestamp_relative(buf, sizeof(buf), x));
41bc83ed 596 log_debug("%s", buf);
c79e88b3 597 ASSERT_STREQ(buf, "2 months 1 day ago");
45eb4d22
AW
598
599 x = now(CLOCK_REALTIME) - (2*USEC_PER_MONTH + 2*USEC_PER_DAY);
600 assert_se(format_timestamp_relative(buf, sizeof(buf), x));
41bc83ed 601 log_debug("%s", buf);
c79e88b3 602 ASSERT_STREQ(buf, "2 months 2 days ago");
45eb4d22
AW
603
604 /* Weeks and days */
605 x = now(CLOCK_REALTIME) - (1*USEC_PER_WEEK + 1*USEC_PER_DAY);
606 assert_se(format_timestamp_relative(buf, sizeof(buf), x));
41bc83ed 607 log_debug("%s", buf);
c79e88b3 608 ASSERT_STREQ(buf, "1 week 1 day ago");
45eb4d22
AW
609
610 x = now(CLOCK_REALTIME) - (1*USEC_PER_WEEK + 2*USEC_PER_DAY);
611 assert_se(format_timestamp_relative(buf, sizeof(buf), x));
41bc83ed 612 log_debug("%s", buf);
c79e88b3 613 ASSERT_STREQ(buf, "1 week 2 days ago");
45eb4d22
AW
614
615 x = now(CLOCK_REALTIME) - (2*USEC_PER_WEEK + 1*USEC_PER_DAY);
616 assert_se(format_timestamp_relative(buf, sizeof(buf), x));
41bc83ed 617 log_debug("%s", buf);
c79e88b3 618 ASSERT_STREQ(buf, "2 weeks 1 day ago");
45eb4d22
AW
619
620 x = now(CLOCK_REALTIME) - (2*USEC_PER_WEEK + 2*USEC_PER_DAY);
621 assert_se(format_timestamp_relative(buf, sizeof(buf), x));
41bc83ed 622 log_debug("%s", buf);
c79e88b3 623 ASSERT_STREQ(buf, "2 weeks 2 days ago");
45eb4d22
AW
624}
625
64f3419e 626static void test_format_timestamp_one(usec_t val, TimestampStyle style, const char *result) {
1bb4b028 627 char buf[FORMAT_TIMESTAMP_MAX];
4d9685be 628 const char *t;
1bb4b028 629
64f3419e 630 t = format_timestamp_style(buf, sizeof(buf), val, style);
c79e88b3 631 ASSERT_STREQ(t, result);
1bb4b028
LP
632}
633
64f3419e
LP
634TEST(format_timestamp_range) {
635 test_format_timestamp_one(0, TIMESTAMP_UTC, NULL);
636 test_format_timestamp_one(0, TIMESTAMP_DATE, NULL);
637 test_format_timestamp_one(0, TIMESTAMP_US_UTC, NULL);
638
639 test_format_timestamp_one(1, TIMESTAMP_UTC, "Thu 1970-01-01 00:00:00 UTC");
640 test_format_timestamp_one(1, TIMESTAMP_DATE, "Thu 1970-01-01");
641 test_format_timestamp_one(1, TIMESTAMP_US_UTC, "Thu 1970-01-01 00:00:00.000001 UTC");
642
643 test_format_timestamp_one(USEC_PER_SEC, TIMESTAMP_UTC, "Thu 1970-01-01 00:00:01 UTC");
644 test_format_timestamp_one(USEC_PER_SEC, TIMESTAMP_DATE, "Thu 1970-01-01");
645 test_format_timestamp_one(USEC_PER_SEC, TIMESTAMP_US_UTC, "Thu 1970-01-01 00:00:01.000000 UTC");
1bb4b028
LP
646
647#if SIZEOF_TIME_T == 8
64f3419e
LP
648 test_format_timestamp_one(USEC_TIMESTAMP_FORMATTABLE_MAX, TIMESTAMP_UTC, "Thu 9999-12-30 23:59:59 UTC");
649 test_format_timestamp_one(USEC_TIMESTAMP_FORMATTABLE_MAX, TIMESTAMP_DATE, "Thu 9999-12-30");
650 test_format_timestamp_one(USEC_TIMESTAMP_FORMATTABLE_MAX + 1, TIMESTAMP_UTC, "--- XXXX-XX-XX XX:XX:XX UTC");
651 test_format_timestamp_one(USEC_TIMESTAMP_FORMATTABLE_MAX + 1, TIMESTAMP_US_UTC, "--- XXXX-XX-XX XX:XX:XX.XXXXXX UTC");
652 test_format_timestamp_one(USEC_TIMESTAMP_FORMATTABLE_MAX + 1, TIMESTAMP_DATE, "--- XXXX-XX-XX");
1bb4b028 653#elif SIZEOF_TIME_T == 4
bd5770da
YW
654 test_format_timestamp_one(USEC_TIMESTAMP_FORMATTABLE_MAX, TIMESTAMP_UTC, "Mon 2038-01-18 03:14:07 UTC");
655 test_format_timestamp_one(USEC_TIMESTAMP_FORMATTABLE_MAX, TIMESTAMP_DATE, "Mon 2038-01-18");
64f3419e
LP
656 test_format_timestamp_one(USEC_TIMESTAMP_FORMATTABLE_MAX + 1, TIMESTAMP_UTC, "--- XXXX-XX-XX XX:XX:XX UTC");
657 test_format_timestamp_one(USEC_TIMESTAMP_FORMATTABLE_MAX + 1, TIMESTAMP_US_UTC, "--- XXXX-XX-XX XX:XX:XX.XXXXXX UTC");
658 test_format_timestamp_one(USEC_TIMESTAMP_FORMATTABLE_MAX + 1, TIMESTAMP_DATE, "--- XXXX-XX-XX");
1bb4b028
LP
659#endif
660
64f3419e 661 test_format_timestamp_one(USEC_INFINITY, TIMESTAMP_UTC, NULL);
1bb4b028
LP
662}
663
8b51c41f 664static void test_parse_timestamp_one(const char *str, usec_t max_diff, usec_t expected) {
d8f3ad62
YW
665 usec_t usec = USEC_INFINITY;
666 int r;
8b51c41f 667
d8f3ad62 668 r = parse_timestamp(str, &usec);
cfacd245 669 log_debug("/* %s(%s): max_diff="USEC_FMT", expected="USEC_FMT", result="USEC_FMT" */", __func__, str, max_diff, expected, usec);
d8f3ad62 670 assert_se(r >= 0);
8b51c41f
YW
671 assert_se(usec >= expected);
672 assert_se(usec_sub_unsigned(usec, expected) <= max_diff);
673}
674
cfacd245
YW
675static bool time_is_zero(usec_t usec) {
676 const char *s;
677
678 s = FORMAT_TIMESTAMP(usec);
679 return strstr(s, " 00:00:00 ");
680}
681
682static bool timezone_equal(usec_t today, usec_t target) {
683 const char *s, *t, *sz, *tz;
684
685 s = FORMAT_TIMESTAMP(today);
686 t = FORMAT_TIMESTAMP(target);
687 assert_se(sz = strrchr(s, ' '));
688 assert_se(tz = strrchr(t, ' '));
689 log_debug("%s("USEC_FMT", "USEC_FMT") -> %s, %s", __func__, today, target, s, t);
690 return streq(sz, tz);
691}
692
d8f3ad62 693static void test_parse_timestamp_impl(const char *tz) {
ef658a63 694 usec_t today, today2, now_usec;
8b51c41f 695
165655cb
MY
696 /* Invalid: Ensure that systemctl reboot --when=show and --when=cancel
697 * will not result in ambiguities */
698 assert_se(parse_timestamp("show", NULL) == -EINVAL);
699 assert_se(parse_timestamp("cancel", NULL) == -EINVAL);
700
8b51c41f
YW
701 /* UTC */
702 test_parse_timestamp_one("Thu 1970-01-01 00:01 UTC", 0, USEC_PER_MINUTE);
703 test_parse_timestamp_one("Thu 1970-01-01 00:00:01 UTC", 0, USEC_PER_SEC);
704 test_parse_timestamp_one("Thu 1970-01-01 00:00:01.001 UTC", 0, USEC_PER_SEC + 1000);
705 test_parse_timestamp_one("Thu 1970-01-01 00:00:01.0010 UTC", 0, USEC_PER_SEC + 1000);
706
707 test_parse_timestamp_one("Thu 70-01-01 00:01 UTC", 0, USEC_PER_MINUTE);
708 test_parse_timestamp_one("Thu 70-01-01 00:00:01 UTC", 0, USEC_PER_SEC);
709 test_parse_timestamp_one("Thu 70-01-01 00:00:01.001 UTC", 0, USEC_PER_SEC + 1000);
710 test_parse_timestamp_one("Thu 70-01-01 00:00:01.0010 UTC", 0, USEC_PER_SEC + 1000);
711
712 test_parse_timestamp_one("1970-01-01 00:01 UTC", 0, USEC_PER_MINUTE);
713 test_parse_timestamp_one("1970-01-01 00:00:01 UTC", 0, USEC_PER_SEC);
714 test_parse_timestamp_one("1970-01-01 00:00:01.001 UTC", 0, USEC_PER_SEC + 1000);
715 test_parse_timestamp_one("1970-01-01 00:00:01.0010 UTC", 0, USEC_PER_SEC + 1000);
716
717 test_parse_timestamp_one("70-01-01 00:01 UTC", 0, USEC_PER_MINUTE);
718 test_parse_timestamp_one("70-01-01 00:00:01 UTC", 0, USEC_PER_SEC);
719 test_parse_timestamp_one("70-01-01 00:00:01.001 UTC", 0, USEC_PER_SEC + 1000);
720 test_parse_timestamp_one("70-01-01 00:00:01.0010 UTC", 0, USEC_PER_SEC + 1000);
721
ef658a63 722 /* Examples from RFC3339 */
723 test_parse_timestamp_one("1985-04-12T23:20:50.52Z", 0, 482196050 * USEC_PER_SEC + 520000);
724 test_parse_timestamp_one("1996-12-19T16:39:57-08:00", 0, 851042397 * USEC_PER_SEC + 000000);
725 test_parse_timestamp_one("1996-12-20T00:39:57Z", 0, 851042397 * USEC_PER_SEC + 000000);
726 test_parse_timestamp_one("1990-12-31T23:59:60Z", 0, 662688000 * USEC_PER_SEC + 000000);
727 test_parse_timestamp_one("1990-12-31T15:59:60-08:00", 0, 662688000 * USEC_PER_SEC + 000000);
6f5cf415 728 assert_se(parse_timestamp("1937-01-01T12:00:27.87+00:20", NULL) == -ERANGE); /* we don't support pre-epoch timestamps */
ef658a63 729 /* We accept timestamps without seconds as well */
730 test_parse_timestamp_one("1996-12-20T00:39Z", 0, (851042397 - 57) * USEC_PER_SEC + 000000);
731 test_parse_timestamp_one("1990-12-31T15:59-08:00", 0, (662688000-60) * USEC_PER_SEC + 000000);
732 /* We drop day-of-week before parsing the timestamp */
733 test_parse_timestamp_one("Thu 1970-01-01T00:01 UTC", 0, USEC_PER_MINUTE);
734 test_parse_timestamp_one("Thu 1970-01-01T00:00:01 UTC", 0, USEC_PER_SEC);
735 test_parse_timestamp_one("Thu 1970-01-01T00:01Z", 0, USEC_PER_MINUTE);
736 test_parse_timestamp_one("Thu 1970-01-01T00:00:01Z", 0, USEC_PER_SEC);
737 /* RFC3339-style timezones can be welded to all formats */
738 assert_se(parse_timestamp("today UTC", &today) == 0);
739 assert_se(parse_timestamp("todayZ", &today2) == 0);
740 assert_se(today == today2);
741 assert_se(parse_timestamp("today +0200", &today) == 0);
742 assert_se(parse_timestamp("today+02:00", &today2) == 0);
743 assert_se(today == today2);
744
745 /* https://ijmacd.github.io/rfc3339-iso8601/ */
746 test_parse_timestamp_one("2023-09-06 12:49:27-00:00", 0, 1694004567 * USEC_PER_SEC + 000000);
747 test_parse_timestamp_one("2023-09-06 12:49:27.284-00:00", 0, 1694004567 * USEC_PER_SEC + 284000);
748 test_parse_timestamp_one("2023-09-06 12:49:27.284029Z", 0, 1694004567 * USEC_PER_SEC + 284029);
749 test_parse_timestamp_one("2023-09-06 12:49:27.284Z", 0, 1694004567 * USEC_PER_SEC + 284000);
750 test_parse_timestamp_one("2023-09-06 12:49:27.28Z", 0, 1694004567 * USEC_PER_SEC + 280000);
751 test_parse_timestamp_one("2023-09-06 12:49:27.2Z", 0, 1694004567 * USEC_PER_SEC + 200000);
752 test_parse_timestamp_one("2023-09-06 12:49:27Z", 0, 1694004567 * USEC_PER_SEC + 000000);
753 test_parse_timestamp_one("2023-09-06 14:49:27+02:00", 0, 1694004567 * USEC_PER_SEC + 000000);
754 test_parse_timestamp_one("2023-09-06 14:49:27.2+02:00", 0, 1694004567 * USEC_PER_SEC + 200000);
755 test_parse_timestamp_one("2023-09-06 14:49:27.28+02:00", 0, 1694004567 * USEC_PER_SEC + 280000);
756 test_parse_timestamp_one("2023-09-06 14:49:27.284+02:00", 0, 1694004567 * USEC_PER_SEC + 284000);
757 test_parse_timestamp_one("2023-09-06 14:49:27.284029+02:00", 0, 1694004567 * USEC_PER_SEC + 284029);
758 test_parse_timestamp_one("2023-09-06T12:49:27+00:00", 0, 1694004567 * USEC_PER_SEC + 000000);
759 test_parse_timestamp_one("2023-09-06T12:49:27-00:00", 0, 1694004567 * USEC_PER_SEC + 000000);
760 test_parse_timestamp_one("2023-09-06T12:49:27.284+00:00", 0, 1694004567 * USEC_PER_SEC + 284000);
761 test_parse_timestamp_one("2023-09-06T12:49:27.284-00:00", 0, 1694004567 * USEC_PER_SEC + 284000);
762 test_parse_timestamp_one("2023-09-06T12:49:27.284029Z", 0, 1694004567 * USEC_PER_SEC + 284029);
763 test_parse_timestamp_one("2023-09-06T12:49:27.284Z", 0, 1694004567 * USEC_PER_SEC + 284000);
764 test_parse_timestamp_one("2023-09-06T12:49:27.28Z", 0, 1694004567 * USEC_PER_SEC + 280000);
765 test_parse_timestamp_one("2023-09-06T12:49:27.2Z", 0, 1694004567 * USEC_PER_SEC + 200000);
766 test_parse_timestamp_one("2023-09-06T12:49:27Z", 0, 1694004567 * USEC_PER_SEC + 000000);
767 test_parse_timestamp_one("2023-09-06T14:49:27+02:00", 0, 1694004567 * USEC_PER_SEC + 000000);
768 test_parse_timestamp_one("2023-09-06T14:49:27.284+02:00", 0, 1694004567 * USEC_PER_SEC + 284000);
769 test_parse_timestamp_one("2023-09-06T14:49:27.284029+02:00", 0, 1694004567 * USEC_PER_SEC + 284029);
770 test_parse_timestamp_one("2023-09-06T21:34:27+08:45", 0, 1694004567 * USEC_PER_SEC + 000000);
771
8b51c41f
YW
772 if (timezone_is_valid("Asia/Tokyo", LOG_DEBUG)) {
773 /* Asia/Tokyo (+0900) */
774 test_parse_timestamp_one("Thu 1970-01-01 09:01 Asia/Tokyo", 0, USEC_PER_MINUTE);
775 test_parse_timestamp_one("Thu 1970-01-01 09:00:01 Asia/Tokyo", 0, USEC_PER_SEC);
776 test_parse_timestamp_one("Thu 1970-01-01 09:00:01.001 Asia/Tokyo", 0, USEC_PER_SEC + 1000);
777 test_parse_timestamp_one("Thu 1970-01-01 09:00:01.0010 Asia/Tokyo", 0, USEC_PER_SEC + 1000);
778
779 test_parse_timestamp_one("Thu 70-01-01 09:01 Asia/Tokyo", 0, USEC_PER_MINUTE);
780 test_parse_timestamp_one("Thu 70-01-01 09:00:01 Asia/Tokyo", 0, USEC_PER_SEC);
781 test_parse_timestamp_one("Thu 70-01-01 09:00:01.001 Asia/Tokyo", 0, USEC_PER_SEC + 1000);
782 test_parse_timestamp_one("Thu 70-01-01 09:00:01.0010 Asia/Tokyo", 0, USEC_PER_SEC + 1000);
783
784 test_parse_timestamp_one("1970-01-01 09:01 Asia/Tokyo", 0, USEC_PER_MINUTE);
785 test_parse_timestamp_one("1970-01-01 09:00:01 Asia/Tokyo", 0, USEC_PER_SEC);
786 test_parse_timestamp_one("1970-01-01 09:00:01.001 Asia/Tokyo", 0, USEC_PER_SEC + 1000);
787 test_parse_timestamp_one("1970-01-01 09:00:01.0010 Asia/Tokyo", 0, USEC_PER_SEC + 1000);
788
789 test_parse_timestamp_one("70-01-01 09:01 Asia/Tokyo", 0, USEC_PER_MINUTE);
790 test_parse_timestamp_one("70-01-01 09:00:01 Asia/Tokyo", 0, USEC_PER_SEC);
791 test_parse_timestamp_one("70-01-01 09:00:01.001 Asia/Tokyo", 0, USEC_PER_SEC + 1000);
792 test_parse_timestamp_one("70-01-01 09:00:01.0010 Asia/Tokyo", 0, USEC_PER_SEC + 1000);
d8f3ad62 793 }
8b51c41f 794
d8f3ad62 795 if (streq_ptr(tz, "Asia/Tokyo")) {
8b51c41f
YW
796 /* JST (+0900) */
797 test_parse_timestamp_one("Thu 1970-01-01 09:01 JST", 0, USEC_PER_MINUTE);
798 test_parse_timestamp_one("Thu 1970-01-01 09:00:01 JST", 0, USEC_PER_SEC);
799 test_parse_timestamp_one("Thu 1970-01-01 09:00:01.001 JST", 0, USEC_PER_SEC + 1000);
800 test_parse_timestamp_one("Thu 1970-01-01 09:00:01.0010 JST", 0, USEC_PER_SEC + 1000);
801
802 test_parse_timestamp_one("Thu 70-01-01 09:01 JST", 0, USEC_PER_MINUTE);
803 test_parse_timestamp_one("Thu 70-01-01 09:00:01 JST", 0, USEC_PER_SEC);
804 test_parse_timestamp_one("Thu 70-01-01 09:00:01.001 JST", 0, USEC_PER_SEC + 1000);
805 test_parse_timestamp_one("Thu 70-01-01 09:00:01.0010 JST", 0, USEC_PER_SEC + 1000);
806
807 test_parse_timestamp_one("1970-01-01 09:01 JST", 0, USEC_PER_MINUTE);
808 test_parse_timestamp_one("1970-01-01 09:00:01 JST", 0, USEC_PER_SEC);
809 test_parse_timestamp_one("1970-01-01 09:00:01.001 JST", 0, USEC_PER_SEC + 1000);
810 test_parse_timestamp_one("1970-01-01 09:00:01.0010 JST", 0, USEC_PER_SEC + 1000);
811
812 test_parse_timestamp_one("70-01-01 09:01 JST", 0, USEC_PER_MINUTE);
813 test_parse_timestamp_one("70-01-01 09:00:01 JST", 0, USEC_PER_SEC);
814 test_parse_timestamp_one("70-01-01 09:00:01.001 JST", 0, USEC_PER_SEC + 1000);
815 test_parse_timestamp_one("70-01-01 09:00:01.0010 JST", 0, USEC_PER_SEC + 1000);
8b51c41f
YW
816 }
817
818 if (timezone_is_valid("America/New_York", LOG_DEBUG)) {
819 /* America/New_York (-0500) */
820 test_parse_timestamp_one("Wed 1969-12-31 19:01 America/New_York", 0, USEC_PER_MINUTE);
821 test_parse_timestamp_one("Wed 1969-12-31 19:00:01 America/New_York", 0, USEC_PER_SEC);
822 test_parse_timestamp_one("Wed 1969-12-31 19:00:01.001 America/New_York", 0, USEC_PER_SEC + 1000);
823 test_parse_timestamp_one("Wed 1969-12-31 19:00:01.0010 America/New_York", 0, USEC_PER_SEC + 1000);
824
825 test_parse_timestamp_one("Wed 69-12-31 19:01 America/New_York", 0, USEC_PER_MINUTE);
826 test_parse_timestamp_one("Wed 69-12-31 19:00:01 America/New_York", 0, USEC_PER_SEC);
827 test_parse_timestamp_one("Wed 69-12-31 19:00:01.001 America/New_York", 0, USEC_PER_SEC + 1000);
828 test_parse_timestamp_one("Wed 69-12-31 19:00:01.0010 America/New_York", 0, USEC_PER_SEC + 1000);
829
830 test_parse_timestamp_one("1969-12-31 19:01 America/New_York", 0, USEC_PER_MINUTE);
831 test_parse_timestamp_one("1969-12-31 19:00:01 America/New_York", 0, USEC_PER_SEC);
832 test_parse_timestamp_one("1969-12-31 19:00:01.001 America/New_York", 0, USEC_PER_SEC + 1000);
833 test_parse_timestamp_one("1969-12-31 19:00:01.0010 America/New_York", 0, USEC_PER_SEC + 1000);
834
835 test_parse_timestamp_one("69-12-31 19:01 America/New_York", 0, USEC_PER_MINUTE);
836 test_parse_timestamp_one("69-12-31 19:00:01 America/New_York", 0, USEC_PER_SEC);
837 test_parse_timestamp_one("69-12-31 19:00:01.001 America/New_York", 0, USEC_PER_SEC + 1000);
838 test_parse_timestamp_one("69-12-31 19:00:01.0010 America/New_York", 0, USEC_PER_SEC + 1000);
d8f3ad62 839 }
8b51c41f 840
d8f3ad62 841 if (streq_ptr(tz, "America/New_York")) {
8b51c41f
YW
842 /* EST (-0500) */
843 test_parse_timestamp_one("Wed 1969-12-31 19:01 EST", 0, USEC_PER_MINUTE);
844 test_parse_timestamp_one("Wed 1969-12-31 19:00:01 EST", 0, USEC_PER_SEC);
845 test_parse_timestamp_one("Wed 1969-12-31 19:00:01.001 EST", 0, USEC_PER_SEC + 1000);
846 test_parse_timestamp_one("Wed 1969-12-31 19:00:01.0010 EST", 0, USEC_PER_SEC + 1000);
847
848 test_parse_timestamp_one("Wed 69-12-31 19:01 EST", 0, USEC_PER_MINUTE);
849 test_parse_timestamp_one("Wed 69-12-31 19:00:01 EST", 0, USEC_PER_SEC);
850 test_parse_timestamp_one("Wed 69-12-31 19:00:01.001 EST", 0, USEC_PER_SEC + 1000);
851 test_parse_timestamp_one("Wed 69-12-31 19:00:01.0010 EST", 0, USEC_PER_SEC + 1000);
852
853 test_parse_timestamp_one("1969-12-31 19:01 EST", 0, USEC_PER_MINUTE);
854 test_parse_timestamp_one("1969-12-31 19:00:01 EST", 0, USEC_PER_SEC);
855 test_parse_timestamp_one("1969-12-31 19:00:01.001 EST", 0, USEC_PER_SEC + 1000);
856 test_parse_timestamp_one("1969-12-31 19:00:01.0010 EST", 0, USEC_PER_SEC + 1000);
857
858 test_parse_timestamp_one("69-12-31 19:01 EST", 0, USEC_PER_MINUTE);
859 test_parse_timestamp_one("69-12-31 19:00:01 EST", 0, USEC_PER_SEC);
860 test_parse_timestamp_one("69-12-31 19:00:01.001 EST", 0, USEC_PER_SEC + 1000);
861 test_parse_timestamp_one("69-12-31 19:00:01.0010 EST", 0, USEC_PER_SEC + 1000);
8b51c41f
YW
862 }
863
eb87d3e1
YW
864 if (timezone_is_valid("NZ", LOG_DEBUG)) {
865 /* NZ (+1200) */
866 test_parse_timestamp_one("Thu 1970-01-01 12:01 NZ", 0, USEC_PER_MINUTE);
867 test_parse_timestamp_one("Thu 1970-01-01 12:00:01 NZ", 0, USEC_PER_SEC);
868 test_parse_timestamp_one("Thu 1970-01-01 12:00:01.001 NZ", 0, USEC_PER_SEC + 1000);
869 test_parse_timestamp_one("Thu 1970-01-01 12:00:01.0010 NZ", 0, USEC_PER_SEC + 1000);
870
871 test_parse_timestamp_one("Thu 70-01-01 12:01 NZ", 0, USEC_PER_MINUTE);
872 test_parse_timestamp_one("Thu 70-01-01 12:00:01 NZ", 0, USEC_PER_SEC);
873 test_parse_timestamp_one("Thu 70-01-01 12:00:01.001 NZ", 0, USEC_PER_SEC + 1000);
874 test_parse_timestamp_one("Thu 70-01-01 12:00:01.0010 NZ", 0, USEC_PER_SEC + 1000);
875
876 test_parse_timestamp_one("1970-01-01 12:01 NZ", 0, USEC_PER_MINUTE);
877 test_parse_timestamp_one("1970-01-01 12:00:01 NZ", 0, USEC_PER_SEC);
878 test_parse_timestamp_one("1970-01-01 12:00:01.001 NZ", 0, USEC_PER_SEC + 1000);
879 test_parse_timestamp_one("1970-01-01 12:00:01.0010 NZ", 0, USEC_PER_SEC + 1000);
880
881 test_parse_timestamp_one("70-01-01 12:01 NZ", 0, USEC_PER_MINUTE);
882 test_parse_timestamp_one("70-01-01 12:00:01 NZ", 0, USEC_PER_SEC);
883 test_parse_timestamp_one("70-01-01 12:00:01.001 NZ", 0, USEC_PER_SEC + 1000);
884 test_parse_timestamp_one("70-01-01 12:00:01.0010 NZ", 0, USEC_PER_SEC + 1000);
885 }
886
8b51c41f
YW
887 /* -06 */
888 test_parse_timestamp_one("Wed 1969-12-31 18:01 -06", 0, USEC_PER_MINUTE);
889 test_parse_timestamp_one("Wed 1969-12-31 18:00:01 -06", 0, USEC_PER_SEC);
890 test_parse_timestamp_one("Wed 1969-12-31 18:00:01.001 -06", 0, USEC_PER_SEC + 1000);
891 test_parse_timestamp_one("Wed 1969-12-31 18:00:01.0010 -06", 0, USEC_PER_SEC + 1000);
892
893 test_parse_timestamp_one("Wed 69-12-31 18:01 -06", 0, USEC_PER_MINUTE);
894 test_parse_timestamp_one("Wed 69-12-31 18:00:01 -06", 0, USEC_PER_SEC);
895 test_parse_timestamp_one("Wed 69-12-31 18:00:01.001 -06", 0, USEC_PER_SEC + 1000);
896 test_parse_timestamp_one("Wed 69-12-31 18:00:01.0010 -06", 0, USEC_PER_SEC + 1000);
897
898 test_parse_timestamp_one("1969-12-31 18:01 -06", 0, USEC_PER_MINUTE);
899 test_parse_timestamp_one("1969-12-31 18:00:01 -06", 0, USEC_PER_SEC);
900 test_parse_timestamp_one("1969-12-31 18:00:01.001 -06", 0, USEC_PER_SEC + 1000);
901 test_parse_timestamp_one("1969-12-31 18:00:01.0010 -06", 0, USEC_PER_SEC + 1000);
902
903 test_parse_timestamp_one("69-12-31 18:01 -06", 0, USEC_PER_MINUTE);
904 test_parse_timestamp_one("69-12-31 18:00:01 -06", 0, USEC_PER_SEC);
905 test_parse_timestamp_one("69-12-31 18:00:01.001 -06", 0, USEC_PER_SEC + 1000);
906 test_parse_timestamp_one("69-12-31 18:00:01.0010 -06", 0, USEC_PER_SEC + 1000);
907
908 /* -0600 */
909 test_parse_timestamp_one("Wed 1969-12-31 18:01 -0600", 0, USEC_PER_MINUTE);
910 test_parse_timestamp_one("Wed 1969-12-31 18:00:01 -0600", 0, USEC_PER_SEC);
911 test_parse_timestamp_one("Wed 1969-12-31 18:00:01.001 -0600", 0, USEC_PER_SEC + 1000);
912 test_parse_timestamp_one("Wed 1969-12-31 18:00:01.0010 -0600", 0, USEC_PER_SEC + 1000);
913
914 test_parse_timestamp_one("Wed 69-12-31 18:01 -0600", 0, USEC_PER_MINUTE);
915 test_parse_timestamp_one("Wed 69-12-31 18:00:01 -0600", 0, USEC_PER_SEC);
916 test_parse_timestamp_one("Wed 69-12-31 18:00:01.001 -0600", 0, USEC_PER_SEC + 1000);
917 test_parse_timestamp_one("Wed 69-12-31 18:00:01.0010 -0600", 0, USEC_PER_SEC + 1000);
918
919 test_parse_timestamp_one("1969-12-31 18:01 -0600", 0, USEC_PER_MINUTE);
920 test_parse_timestamp_one("1969-12-31 18:00:01 -0600", 0, USEC_PER_SEC);
921 test_parse_timestamp_one("1969-12-31 18:00:01.001 -0600", 0, USEC_PER_SEC + 1000);
922 test_parse_timestamp_one("1969-12-31 18:00:01.0010 -0600", 0, USEC_PER_SEC + 1000);
923
924 test_parse_timestamp_one("69-12-31 18:01 -0600", 0, USEC_PER_MINUTE);
925 test_parse_timestamp_one("69-12-31 18:00:01 -0600", 0, USEC_PER_SEC);
926 test_parse_timestamp_one("69-12-31 18:00:01.001 -0600", 0, USEC_PER_SEC + 1000);
927 test_parse_timestamp_one("69-12-31 18:00:01.0010 -0600", 0, USEC_PER_SEC + 1000);
928
929 /* -06:00 */
930 test_parse_timestamp_one("Wed 1969-12-31 18:01 -06:00", 0, USEC_PER_MINUTE);
931 test_parse_timestamp_one("Wed 1969-12-31 18:00:01 -06:00", 0, USEC_PER_SEC);
932 test_parse_timestamp_one("Wed 1969-12-31 18:00:01.001 -06:00", 0, USEC_PER_SEC + 1000);
933 test_parse_timestamp_one("Wed 1969-12-31 18:00:01.0010 -06:00", 0, USEC_PER_SEC + 1000);
934
935 test_parse_timestamp_one("Wed 69-12-31 18:01 -06:00", 0, USEC_PER_MINUTE);
936 test_parse_timestamp_one("Wed 69-12-31 18:00:01 -06:00", 0, USEC_PER_SEC);
937 test_parse_timestamp_one("Wed 69-12-31 18:00:01.001 -06:00", 0, USEC_PER_SEC + 1000);
938 test_parse_timestamp_one("Wed 69-12-31 18:00:01.0010 -06:00", 0, USEC_PER_SEC + 1000);
939
940 test_parse_timestamp_one("1969-12-31 18:01 -06:00", 0, USEC_PER_MINUTE);
941 test_parse_timestamp_one("1969-12-31 18:00:01 -06:00", 0, USEC_PER_SEC);
942 test_parse_timestamp_one("1969-12-31 18:00:01.001 -06:00", 0, USEC_PER_SEC + 1000);
943 test_parse_timestamp_one("1969-12-31 18:00:01.0010 -06:00", 0, USEC_PER_SEC + 1000);
944
945 test_parse_timestamp_one("69-12-31 18:01 -06:00", 0, USEC_PER_MINUTE);
946 test_parse_timestamp_one("69-12-31 18:00:01 -06:00", 0, USEC_PER_SEC);
947 test_parse_timestamp_one("69-12-31 18:00:01.001 -06:00", 0, USEC_PER_SEC + 1000);
948 test_parse_timestamp_one("69-12-31 18:00:01.0010 -06:00", 0, USEC_PER_SEC + 1000);
949
950 /* without date */
951 assert_se(parse_timestamp("today", &today) == 0);
cfacd245
YW
952 if (time_is_zero(today)) {
953 test_parse_timestamp_one("00:01", 0, today + USEC_PER_MINUTE);
954 test_parse_timestamp_one("00:00:01", 0, today + USEC_PER_SEC);
955 test_parse_timestamp_one("00:00:01.001", 0, today + USEC_PER_SEC + 1000);
956 test_parse_timestamp_one("00:00:01.0010", 0, today + USEC_PER_SEC + 1000);
957
958 if (timezone_equal(today, today + USEC_PER_DAY) && time_is_zero(today + USEC_PER_DAY))
959 test_parse_timestamp_one("tomorrow", 0, today + USEC_PER_DAY);
960 if (timezone_equal(today, today - USEC_PER_DAY) && time_is_zero(today - USEC_PER_DAY))
961 test_parse_timestamp_one("yesterday", 0, today - USEC_PER_DAY);
962 }
8b51c41f 963
eb87d3e1
YW
964 /* with timezone */
965 if (tz) {
966 _cleanup_free_ char *s = NULL;
967
278e3adf 968 ASSERT_NOT_NULL((s = strjoin("Fri 2012-11-23 23:02:15 ", tz)));
eb87d3e1
YW
969 ASSERT_OK(parse_timestamp(s, NULL));
970 }
971
8b51c41f
YW
972 /* relative */
973 assert_se(parse_timestamp("now", &now_usec) == 0);
974 test_parse_timestamp_one("+5hours", USEC_PER_MINUTE, now_usec + 5 * USEC_PER_HOUR);
975 if (now_usec >= 10 * USEC_PER_DAY)
976 test_parse_timestamp_one("-10days", USEC_PER_MINUTE, now_usec - 10 * USEC_PER_DAY);
977 test_parse_timestamp_one("2weeks left", USEC_PER_MINUTE, now_usec + 2 * USEC_PER_WEEK);
978 if (now_usec >= 30 * USEC_PER_MINUTE)
979 test_parse_timestamp_one("30minutes ago", USEC_PER_MINUTE, now_usec - 30 * USEC_PER_MINUTE);
980}
981
d8f3ad62
YW
982TEST(parse_timestamp) {
983 test_parse_timestamp_impl(NULL);
984}
985
986static void test_parse_timestamp_with_tz_one(const char *tz) {
987 const char *saved_tz, *colon_tz;
988
989 if (!timezone_is_valid(tz, LOG_DEBUG))
990 return;
991
992 log_info("/* %s(%s) */", __func__, tz);
993
994 saved_tz = getenv("TZ");
995
996 assert_se(colon_tz = strjoina(":", tz));
997 assert_se(setenv("TZ", colon_tz, 1) >= 0);
998 tzset();
999 log_debug("%s: tzname[0]=%s, tzname[1]=%s", tz, strempty(tzname[0]), strempty(tzname[1]));
1000
1001 test_parse_timestamp_impl(tz);
1002
1003 assert_se(set_unset_env("TZ", saved_tz, true) == 0);
1004 tzset();
1005}
1006
1007TEST(parse_timestamp_with_tz) {
1008 _cleanup_strv_free_ char **timezones = NULL;
1009
e3201a69
FS
1010 test_parse_timestamp_with_tz_one("UTC");
1011
1012 if (!slow_tests_enabled())
1013 return (void) log_tests_skipped("slow tests are disabled");
1014
d8f3ad62
YW
1015 assert_se(get_timezones(&timezones) >= 0);
1016 STRV_FOREACH(tz, timezones)
1017 test_parse_timestamp_with_tz_one(*tz);
1018}
1019
4f7452a8 1020TEST(deserialize_dual_timestamp) {
9c0565b2
ZJS
1021 int r;
1022 dual_timestamp t;
1023
d68c645b 1024 r = deserialize_dual_timestamp("1234 5678", &t);
9c0565b2
ZJS
1025 assert_se(r == 0);
1026 assert_se(t.realtime == 1234);
1027 assert_se(t.monotonic == 5678);
1028
d68c645b 1029 r = deserialize_dual_timestamp("1234x 5678", &t);
9c0565b2
ZJS
1030 assert_se(r == -EINVAL);
1031
d68c645b 1032 r = deserialize_dual_timestamp("1234 5678y", &t);
9c0565b2
ZJS
1033 assert_se(r == -EINVAL);
1034
d68c645b 1035 r = deserialize_dual_timestamp("-1234 5678", &t);
9c0565b2
ZJS
1036 assert_se(r == -EINVAL);
1037
d68c645b 1038 r = deserialize_dual_timestamp("1234 -5678", &t);
9c0565b2
ZJS
1039 assert_se(r == -EINVAL);
1040
1041 /* Check that output wasn't modified. */
1042 assert_se(t.realtime == 1234);
1043 assert_se(t.monotonic == 5678);
1044
d68c645b 1045 r = deserialize_dual_timestamp("+123 567", &t);
9c0565b2
ZJS
1046 assert_se(r == 0);
1047 assert_se(t.realtime == 123);
1048 assert_se(t.monotonic == 567);
1049
1050 /* Check that we get "infinity" on overflow. */
d68c645b 1051 r = deserialize_dual_timestamp("18446744073709551617 0", &t);
9c0565b2
ZJS
1052 assert_se(r == 0);
1053 assert_se(t.realtime == USEC_INFINITY);
1054 assert_se(t.monotonic == 0);
1055}
1056
1007ec60
LP
1057static void assert_similar(usec_t a, usec_t b) {
1058 usec_t d;
1059
1060 if (a > b)
1061 d = a - b;
1062 else
1063 d = b - a;
1064
060d9c61 1065 assert_se(d < 10*USEC_PER_SEC);
1007ec60
LP
1066}
1067
4f7452a8 1068TEST(usec_shift_clock) {
1007ec60
LP
1069 usec_t rt, mn, bt;
1070
1071 rt = now(CLOCK_REALTIME);
1072 mn = now(CLOCK_MONOTONIC);
ba4e0427 1073 bt = now(CLOCK_BOOTTIME);
1007ec60
LP
1074
1075 assert_se(usec_shift_clock(USEC_INFINITY, CLOCK_REALTIME, CLOCK_MONOTONIC) == USEC_INFINITY);
1076
1077 assert_similar(usec_shift_clock(rt + USEC_PER_HOUR, CLOCK_REALTIME, CLOCK_MONOTONIC), mn + USEC_PER_HOUR);
ba4e0427 1078 assert_similar(usec_shift_clock(rt + 2*USEC_PER_HOUR, CLOCK_REALTIME, CLOCK_BOOTTIME), bt + 2*USEC_PER_HOUR);
1007ec60
LP
1079 assert_se(usec_shift_clock(rt + 3*USEC_PER_HOUR, CLOCK_REALTIME, CLOCK_REALTIME_ALARM) == rt + 3*USEC_PER_HOUR);
1080
1081 assert_similar(usec_shift_clock(mn + 4*USEC_PER_HOUR, CLOCK_MONOTONIC, CLOCK_REALTIME_ALARM), rt + 4*USEC_PER_HOUR);
ba4e0427 1082 assert_similar(usec_shift_clock(mn + 5*USEC_PER_HOUR, CLOCK_MONOTONIC, CLOCK_BOOTTIME), bt + 5*USEC_PER_HOUR);
1007ec60
LP
1083 assert_se(usec_shift_clock(mn + 6*USEC_PER_HOUR, CLOCK_MONOTONIC, CLOCK_MONOTONIC) == mn + 6*USEC_PER_HOUR);
1084
ba4e0427
LP
1085 assert_similar(usec_shift_clock(bt + 7*USEC_PER_HOUR, CLOCK_BOOTTIME, CLOCK_MONOTONIC), mn + 7*USEC_PER_HOUR);
1086 assert_similar(usec_shift_clock(bt + 8*USEC_PER_HOUR, CLOCK_BOOTTIME, CLOCK_REALTIME_ALARM), rt + 8*USEC_PER_HOUR);
1087 assert_se(usec_shift_clock(bt + 9*USEC_PER_HOUR, CLOCK_BOOTTIME, CLOCK_BOOTTIME) == bt + 9*USEC_PER_HOUR);
1007ec60
LP
1088
1089 if (mn > USEC_PER_MINUTE) {
1090 assert_similar(usec_shift_clock(rt - 30 * USEC_PER_SEC, CLOCK_REALTIME_ALARM, CLOCK_MONOTONIC), mn - 30 * USEC_PER_SEC);
ba4e0427 1091 assert_similar(usec_shift_clock(rt - 50 * USEC_PER_SEC, CLOCK_REALTIME, CLOCK_BOOTTIME), bt - 50 * USEC_PER_SEC);
1007ec60
LP
1092 }
1093}
1094
4f7452a8 1095TEST(in_utc_timezone) {
4d5ad9d9
JJ
1096 const char *tz = getenv("TZ");
1097
9a9a4f10
LP
1098 assert_se(setenv("TZ", ":UTC", 1) >= 0);
1099 assert_se(in_utc_timezone());
c79e88b3
IK
1100 ASSERT_STREQ(tzname[0], "UTC");
1101 ASSERT_STREQ(tzname[1], "UTC");
9a9a4f10
LP
1102 assert_se(timezone == 0);
1103 assert_se(daylight == 0);
1104
437f48a4 1105 assert_se(setenv("TZ", ":Europe/Berlin", 1) >= 0);
9a9a4f10 1106 assert_se(!in_utc_timezone());
c79e88b3
IK
1107 ASSERT_STREQ(tzname[0], "CET");
1108 ASSERT_STREQ(tzname[1], "CEST");
9a9a4f10 1109
4d5ad9d9
JJ
1110 assert_se(set_unset_env("TZ", tz, true) == 0);
1111 tzset();
9a9a4f10
LP
1112}
1113
4f7452a8 1114TEST(map_clock_usec) {
d3926f9a
LP
1115 usec_t nowr, x, y, z;
1116
4f7452a8 1117 x = nowr = now(CLOCK_REALTIME); /* right now */
d3926f9a
LP
1118 y = map_clock_usec(x, CLOCK_REALTIME, CLOCK_MONOTONIC);
1119 z = map_clock_usec(y, CLOCK_MONOTONIC, CLOCK_REALTIME);
1120 /* Converting forth and back will introduce inaccuracies, since we cannot query both clocks atomically, but it should be small. Even on the slowest CI smaller than 1h */
1121
1122 assert_se((z > x ? z - x : x - z) < USEC_PER_HOUR);
1123
1124 assert_se(nowr < USEC_INFINITY - USEC_PER_DAY*7); /* overflow check */
1125 x = nowr + USEC_PER_DAY*7; /* 1 week from now */
1126 y = map_clock_usec(x, CLOCK_REALTIME, CLOCK_MONOTONIC);
b8e0dd39 1127 assert_se(timestamp_is_set(y));
d3926f9a 1128 z = map_clock_usec(y, CLOCK_MONOTONIC, CLOCK_REALTIME);
b8e0dd39 1129 assert_se(timestamp_is_set(z));
d3926f9a
LP
1130 assert_se((z > x ? z - x : x - z) < USEC_PER_HOUR);
1131
1132 assert_se(nowr > USEC_PER_DAY * 7); /* underflow check */
1133 x = nowr - USEC_PER_DAY*7; /* 1 week ago */
1134 y = map_clock_usec(x, CLOCK_REALTIME, CLOCK_MONOTONIC);
1135 if (y != 0) { /* might underflow if machine is not up long enough for the monotonic clock to be beyond 1w */
1136 assert_se(y < USEC_INFINITY);
1137 z = map_clock_usec(y, CLOCK_MONOTONIC, CLOCK_REALTIME);
b8e0dd39 1138 assert_se(timestamp_is_set(z));
d3926f9a
LP
1139 assert_se((z > x ? z - x : x - z) < USEC_PER_HOUR);
1140 }
1141}
1142
8b51c41f
YW
1143static void test_timezone_offset_change_one(const char *utc, const char *pretty) {
1144 usec_t x, y, z;
1145 char *s;
1146
1147 assert_se(parse_timestamp(utc, &x) >= 0);
1148
1149 s = FORMAT_TIMESTAMP_STYLE(x, TIMESTAMP_UTC);
1150 assert_se(parse_timestamp(s, &y) >= 0);
1151 log_debug("%s -> " USEC_FMT " -> %s -> " USEC_FMT, utc, x, s, y);
c79e88b3 1152 ASSERT_STREQ(s, utc);
8b51c41f
YW
1153 assert_se(x == y);
1154
1155 assert_se(parse_timestamp(pretty, &y) >= 0);
1156 s = FORMAT_TIMESTAMP_STYLE(y, TIMESTAMP_PRETTY);
1157 assert_se(parse_timestamp(s, &z) >= 0);
1158 log_debug("%s -> " USEC_FMT " -> %s -> " USEC_FMT, pretty, y, s, z);
c79e88b3 1159 ASSERT_STREQ(s, pretty);
8b51c41f
YW
1160 assert_se(x == y);
1161 assert_se(x == z);
1162}
1163
1164TEST(timezone_offset_change) {
1165 const char *tz = getenv("TZ");
1166
1167 /* See issue #26370. */
1168
1169 if (timezone_is_valid("Africa/Casablanca", LOG_DEBUG)) {
1170 assert_se(setenv("TZ", ":Africa/Casablanca", 1) >= 0);
1171 tzset();
1172 log_debug("Africa/Casablanca: tzname[0]=%s, tzname[1]=%s", strempty(tzname[0]), strempty(tzname[1]));
1173
1174 test_timezone_offset_change_one("Sun 2015-10-25 01:59:59 UTC", "Sun 2015-10-25 02:59:59 +01");
1175 test_timezone_offset_change_one("Sun 2015-10-25 02:00:00 UTC", "Sun 2015-10-25 02:00:00 +00");
1176 test_timezone_offset_change_one("Sun 2018-06-17 01:59:59 UTC", "Sun 2018-06-17 01:59:59 +00");
1177 test_timezone_offset_change_one("Sun 2018-06-17 02:00:00 UTC", "Sun 2018-06-17 03:00:00 +01");
1178 test_timezone_offset_change_one("Sun 2018-10-28 01:59:59 UTC", "Sun 2018-10-28 02:59:59 +01");
1179 test_timezone_offset_change_one("Sun 2018-10-28 02:00:00 UTC", "Sun 2018-10-28 03:00:00 +01");
1180 }
1181
1182 if (timezone_is_valid("Asia/Atyrau", LOG_DEBUG)) {
1183 assert_se(setenv("TZ", ":Asia/Atyrau", 1) >= 0);
1184 tzset();
1185 log_debug("Asia/Atyrau: tzname[0]=%s, tzname[1]=%s", strempty(tzname[0]), strempty(tzname[1]));
1186
1187 test_timezone_offset_change_one("Sat 2004-03-27 21:59:59 UTC", "Sun 2004-03-28 01:59:59 +04");
1188 test_timezone_offset_change_one("Sat 2004-03-27 22:00:00 UTC", "Sun 2004-03-28 03:00:00 +05");
1189 test_timezone_offset_change_one("Sat 2004-10-30 21:59:59 UTC", "Sun 2004-10-31 02:59:59 +05");
1190 test_timezone_offset_change_one("Sat 2004-10-30 22:00:00 UTC", "Sun 2004-10-31 03:00:00 +05");
1191 }
1192
1193 if (timezone_is_valid("Chile/EasterIsland", LOG_DEBUG)) {
1194 assert_se(setenv("TZ", ":Chile/EasterIsland", 1) >= 0);
1195 tzset();
1196 log_debug("Chile/EasterIsland: tzname[0]=%s, tzname[1]=%s", strempty(tzname[0]), strempty(tzname[1]));
1197
1198 test_timezone_offset_change_one("Sun 1981-10-11 03:59:59 UTC", "Sat 1981-10-10 20:59:59 -07");
1199 test_timezone_offset_change_one("Sun 1981-10-11 04:00:00 UTC", "Sat 1981-10-10 22:00:00 -06");
1200 test_timezone_offset_change_one("Sun 1982-03-14 02:59:59 UTC", "Sat 1982-03-13 20:59:59 -06");
1201 test_timezone_offset_change_one("Sun 1982-03-14 03:00:00 UTC", "Sat 1982-03-13 21:00:00 -06");
1202 }
1203
1204 assert_se(set_unset_env("TZ", tz, true) == 0);
1205 tzset();
1206}
1207
6f5cf415
LP
1208static usec_t absdiff(usec_t a, usec_t b) {
1209 return a > b ? a - b : b - a;
1210}
1211
1212TEST(mktime_or_timegm_usec) {
1213
1214 usec_t n = now(CLOCK_REALTIME), m;
1215 struct tm tm;
1216
1217 assert_se(localtime_or_gmtime_usec(n, /* utc= */ false, &tm) >= 0);
1218 assert_se(mktime_or_timegm_usec(&tm, /* utc= */ false, &m) >= 0);
1219 assert_se(absdiff(n, m) < 2 * USEC_PER_DAY);
1220
1221 assert_se(localtime_or_gmtime_usec(n, /* utc= */ true, &tm) >= 0);
1222 assert_se(mktime_or_timegm_usec(&tm, /* utc= */ true, &m) >= 0);
1223 assert_se(absdiff(n, m) < USEC_PER_SEC);
1224
1225 /* This definitely should fail, because we refuse dates before the UNIX epoch */
1226 tm = (struct tm) {
1227 .tm_mday = 15,
1228 .tm_mon = 11,
1229 .tm_year = 1969 - 1900,
1230 };
1231
1232 assert_se(mktime_or_timegm_usec(&tm, /* utc= */ true, NULL) == -ERANGE);
1233}
1234
99839c7e 1235static int intro(void) {
1e902c34
LB
1236 /* Tests have hard-coded results that do not expect a specific timezone to be set by the caller */
1237 assert_se(unsetenv("TZ") >= 0);
1238
c4834ffa
LP
1239 log_info("realtime=" USEC_FMT "\n"
1240 "monotonic=" USEC_FMT "\n"
1241 "boottime=" USEC_FMT "\n",
1242 now(CLOCK_REALTIME),
1243 now(CLOCK_MONOTONIC),
ba4e0427 1244 now(CLOCK_BOOTTIME));
c4834ffa 1245
2d60169d
LP
1246 /* Ensure time_t is signed */
1247 assert_cc((time_t) -1 < (time_t) 1);
1248
1249 /* Ensure TIME_T_MAX works correctly */
f0e2e0db 1250 uintmax_t x = TIME_T_MAX;
313cefa1 1251 x++;
f21b863e 1252 assert_se((time_t) x < 0);
99839c7e
LP
1253
1254 return EXIT_SUCCESS;
cb0dac05 1255}
4f7452a8 1256
e85fdacc 1257DEFINE_TEST_MAIN_WITH_INTRO(LOG_INFO, intro);