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