]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/test/test-time-util.c
5e01bb2fe3278faff5ada6b6e9d9aac76726e61a
[thirdparty/systemd.git] / src / test / test-time-util.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <stdlib.h>
4 #include "env-util.h"
5 #include "random-util.h"
6 #include "serialize.h"
7 #include "string-util.h"
8 #include "strv.h"
9 #include "tests.h"
10 #include "time-util.h"
11
12 #define TRIAL 100u
13
14 TEST(parse_sec) {
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);
35 assert_se(parse_sec("23us", &u) >= 0);
36 assert_se(u == 23);
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 */
40 assert_se(u == 23);
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);
45 assert_se(parse_sec("+3.1s", &u) >= 0);
46 assert_se(u == 3100 * USEC_PER_MSEC);
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);
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);
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);
67 assert_se(parse_sec(" infinity .7", &u) < 0);
68 assert_se(parse_sec(".3 infinity", &u) < 0);
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);
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);
76 }
77
78 TEST(parse_sec_fix_0) {
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);
84 assert_se(u == USEC_INFINITY);
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
91 TEST(parse_sec_def_infinity) {
92 usec_t u;
93
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
109 TEST(parse_time) {
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);
129
130 assert_se(parse_time("11111111111111y", &u, 1) == -ERANGE);
131 assert_se(parse_time("1.1111111111111y", &u, 1) >= 0);
132 }
133
134 TEST(parse_nsec) {
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);
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);
159 assert_se(parse_nsec("+3.1s", &u) >= 0);
160 assert_se(u == 3100 * NSEC_PER_MSEC);
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);
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);
175 assert_se(parse_nsec(" infinity .7", &u) < 0);
176 assert_se(parse_nsec(".3 infinity", &u) < 0);
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);
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);
192 assert_se(parse_nsec("1111111111111y", &u) == -ERANGE);
193 assert_se(parse_nsec("1.111111111111y", &u) >= 0);
194 }
195
196 static void test_format_timespan_one(usec_t x, usec_t accuracy) {
197 char l[FORMAT_TIMESPAN_MAX];
198 const char *t;
199 usec_t y;
200
201 log_debug(USEC_FMT" (at accuracy "USEC_FMT")", x, accuracy);
202
203 assert_se(t = format_timespan(l, sizeof l, x, accuracy));
204 log_debug(" = <%s>", t);
205
206 assert_se(parse_sec(t, &y) >= 0);
207 log_debug(" = "USEC_FMT, y);
208
209 if (accuracy <= 0)
210 accuracy = 1;
211
212 assert_se(x / accuracy == y / accuracy);
213 }
214
215 static void test_format_timespan_accuracy(usec_t accuracy) {
216 log_info("/* %s accuracy="USEC_FMT" */", __func__, accuracy);
217
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);
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);
239 test_format_timespan_one(USEC_INFINITY, accuracy);
240 }
241
242 TEST(format_timespan) {
243 test_format_timespan_accuracy(1);
244 test_format_timespan_accuracy(USEC_PER_MSEC);
245 test_format_timespan_accuracy(USEC_PER_SEC);
246
247 /* See issue #23928. */
248 _cleanup_free_ char *buf = NULL;
249 assert_se(buf = new(char, 5));
250 assert_se(buf == format_timespan(buf, 5, 100005, 1000));
251 }
252
253 TEST(verify_timezone) {
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
262 TEST(timezone_is_valid) {
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));
266 }
267
268 TEST(get_timezones) {
269 _cleanup_strv_free_ char **zones = NULL;
270 int r;
271
272 r = get_timezones(&zones);
273 assert_se(r == 0);
274
275 STRV_FOREACH(zone, zones) {
276 r = verify_timezone(*zone, LOG_ERR);
277 log_debug_errno(r, "verify_timezone(\"%s\"): %m", *zone);
278 assert_se(r >= 0 || r == -ENOENT);
279 }
280 }
281
282 TEST(usec_add) {
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);
291 }
292
293 TEST(usec_sub_unsigned) {
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
314 TEST(usec_sub_signed) {
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);
319
320 assert_se(usec_sub_signed(USEC_INFINITY-3, -3) == USEC_INFINITY);
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);
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))));
339 }
340
341 TEST(format_timestamp) {
342 for (unsigned i = 0; i < TRIAL; i++) {
343 char buf[CONST_MAX(FORMAT_TIMESTAMP_MAX, FORMAT_TIMESPAN_MAX)];
344 usec_t x, y;
345
346 x = random_u64_range(USEC_TIMESTAMP_FORMATTABLE_MAX - USEC_PER_SEC) + USEC_PER_SEC;
347
348 assert_se(format_timestamp(buf, sizeof(buf), x));
349 log_debug("%s", buf);
350 assert_se(parse_timestamp(buf, &y) >= 0);
351 assert_se(x / USEC_PER_SEC == y / USEC_PER_SEC);
352
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
358 assert_se(format_timestamp_style(buf, sizeof(buf), x, TIMESTAMP_UTC));
359 log_debug("%s", buf);
360 assert_se(parse_timestamp(buf, &y) >= 0);
361 assert_se(x / USEC_PER_SEC == y / USEC_PER_SEC);
362
363 assert_se(format_timestamp_style(buf, sizeof(buf), x, TIMESTAMP_US));
364 log_debug("%s", buf);
365 assert_se(parse_timestamp(buf, &y) >= 0);
366 assert_se(x == y);
367
368 assert_se(format_timestamp_style(buf, sizeof(buf), x, TIMESTAMP_US_UTC));
369 log_debug("%s", buf);
370 assert_se(parse_timestamp(buf, &y) >= 0);
371 assert_se(x == y);
372
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 }
379
380 assert_se(format_timestamp_relative(buf, sizeof(buf), x));
381 log_debug("%s", buf);
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
392 static void test_format_timestamp_impl(usec_t x) {
393 bool success, override;
394 const char *xx, *yy;
395 usec_t y, x_sec, y_sec;
396
397 xx = FORMAT_TIMESTAMP(x);
398 ASSERT_NOT_NULL(xx);
399 ASSERT_OK(parse_timestamp(xx, &y));
400 yy = FORMAT_TIMESTAMP(y);
401 ASSERT_NOT_NULL(yy);
402
403 x_sec = x / USEC_PER_SEC;
404 y_sec = y / USEC_PER_SEC;
405 success = (x_sec == y_sec) && streq(xx, yy);
406 /* Workaround for https://github.com/systemd/systemd/issues/28472
407 * and https://github.com/systemd/systemd/pull/35471. */
408 override = !success &&
409 (STRPTR_IN_SET(tzname[0], "CAT", "EAT", "WET") ||
410 STRPTR_IN_SET(tzname[1], "CAT", "EAT", "WET")) &&
411 (x_sec > y_sec ? x_sec - y_sec : y_sec - x_sec) == 3600; /* 1 hour, ignore fractional second */
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) {
417 if (!success)
418 log_warning("tzname[0]=\"%s\", tzname[1]=\"%s\"", tzname[0], tzname[1]);
419 ASSERT_EQ(x_sec, y_sec);
420 ASSERT_STREQ(xx, yy);
421 }
422 }
423
424 static void test_format_timestamp_loop(void) {
425 test_format_timestamp_impl(USEC_PER_DAY + USEC_PER_SEC);
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);
430
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
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
443 TEST(FORMAT_TIMESTAMP) {
444 test_format_timestamp_loop();
445 }
446
447 static void test_format_timestamp_with_tz_one(const char *tz) {
448 const char *saved_tz, *colon_tz;
449
450 if (!timezone_is_valid(tz, LOG_DEBUG))
451 return;
452
453 log_info("/* %s(%s) */", __func__, tz);
454
455 saved_tz = getenv("TZ");
456
457 assert_se(colon_tz = strjoina(":", tz));
458 assert_se(setenv("TZ", colon_tz, 1) >= 0);
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
468 TEST(FORMAT_TIMESTAMP_with_tz) {
469 _cleanup_strv_free_ char **timezones = NULL;
470
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
476 assert_se(get_timezones(&timezones) >= 0);
477 STRV_FOREACH(tz, timezones)
478 test_format_timestamp_with_tz_one(*tz);
479 }
480
481 TEST(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);
487 assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_REALTIME, true));
488 log_debug("%s", buf);
489 ASSERT_STREQ(buf, "1 year 1 month ago");
490
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);
494 ASSERT_STREQ(buf, "1 year 1 month left");
495
496 x = now(CLOCK_REALTIME) - (1*USEC_PER_YEAR + 2*USEC_PER_MONTH);
497 assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_REALTIME, true));
498 log_debug("%s", buf);
499 ASSERT_STREQ(buf, "1 year 2 months ago");
500
501 x = now(CLOCK_REALTIME) - (2*USEC_PER_YEAR + 1*USEC_PER_MONTH);
502 assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_REALTIME, true));
503 log_debug("%s", buf);
504 ASSERT_STREQ(buf, "2 years 1 month ago");
505
506 x = now(CLOCK_REALTIME) - (2*USEC_PER_YEAR + 2*USEC_PER_MONTH);
507 assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_REALTIME, true));
508 log_debug("%s", buf);
509 ASSERT_STREQ(buf, "2 years 2 months ago");
510
511 /* Months and days */
512 x = now(CLOCK_REALTIME) - (1*USEC_PER_MONTH + 1*USEC_PER_DAY);
513 assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_REALTIME, true));
514 log_debug("%s", buf);
515 ASSERT_STREQ(buf, "1 month 1 day ago");
516
517 x = now(CLOCK_REALTIME) - (1*USEC_PER_MONTH + 2*USEC_PER_DAY);
518 assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_REALTIME, true));
519 log_debug("%s", buf);
520 ASSERT_STREQ(buf, "1 month 2 days ago");
521
522 x = now(CLOCK_REALTIME) - (2*USEC_PER_MONTH + 1*USEC_PER_DAY);
523 assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_REALTIME, true));
524 log_debug("%s", buf);
525 ASSERT_STREQ(buf, "2 months 1 day ago");
526
527 x = now(CLOCK_REALTIME) - (2*USEC_PER_MONTH + 2*USEC_PER_DAY);
528 assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_REALTIME, true));
529 log_debug("%s", buf);
530 ASSERT_STREQ(buf, "2 months 2 days ago");
531
532 /* Weeks and days */
533 x = now(CLOCK_REALTIME) - (1*USEC_PER_WEEK + 1*USEC_PER_DAY);
534 assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_REALTIME, true));
535 log_debug("%s", buf);
536 ASSERT_STREQ(buf, "1 week 1 day ago");
537
538 x = now(CLOCK_REALTIME) - (1*USEC_PER_WEEK + 2*USEC_PER_DAY);
539 assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_REALTIME, true));
540 log_debug("%s", buf);
541 ASSERT_STREQ(buf, "1 week 2 days ago");
542
543 x = now(CLOCK_REALTIME) - (2*USEC_PER_WEEK + 1*USEC_PER_DAY);
544 assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_REALTIME, true));
545 log_debug("%s", buf);
546 ASSERT_STREQ(buf, "2 weeks 1 day ago");
547
548 x = now(CLOCK_REALTIME) - (2*USEC_PER_WEEK + 2*USEC_PER_DAY);
549 assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_REALTIME, true));
550 log_debug("%s", buf);
551 ASSERT_STREQ(buf, "2 weeks 2 days ago");
552 }
553
554 TEST(format_timestamp_relative) {
555 char buf[CONST_MAX(FORMAT_TIMESTAMP_MAX, FORMAT_TIMESPAN_MAX)];
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));
565 log_debug("%s", buf);
566 ASSERT_STREQ(buf, "1 year 1 month ago");
567
568 x = now(CLOCK_REALTIME) - (1*USEC_PER_YEAR + 2*USEC_PER_MONTH);
569 assert_se(format_timestamp_relative(buf, sizeof(buf), x));
570 log_debug("%s", buf);
571 ASSERT_STREQ(buf, "1 year 2 months ago");
572
573 x = now(CLOCK_REALTIME) - (2*USEC_PER_YEAR + 1*USEC_PER_MONTH);
574 assert_se(format_timestamp_relative(buf, sizeof(buf), x));
575 log_debug("%s", buf);
576 ASSERT_STREQ(buf, "2 years 1 month ago");
577
578 x = now(CLOCK_REALTIME) - (2*USEC_PER_YEAR + 2*USEC_PER_MONTH);
579 assert_se(format_timestamp_relative(buf, sizeof(buf), x));
580 log_debug("%s", buf);
581 ASSERT_STREQ(buf, "2 years 2 months ago");
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));
586 log_debug("%s", buf);
587 ASSERT_STREQ(buf, "1 month 1 day ago");
588
589 x = now(CLOCK_REALTIME) - (1*USEC_PER_MONTH + 2*USEC_PER_DAY);
590 assert_se(format_timestamp_relative(buf, sizeof(buf), x));
591 log_debug("%s", buf);
592 ASSERT_STREQ(buf, "1 month 2 days ago");
593
594 x = now(CLOCK_REALTIME) - (2*USEC_PER_MONTH + 1*USEC_PER_DAY);
595 assert_se(format_timestamp_relative(buf, sizeof(buf), x));
596 log_debug("%s", buf);
597 ASSERT_STREQ(buf, "2 months 1 day ago");
598
599 x = now(CLOCK_REALTIME) - (2*USEC_PER_MONTH + 2*USEC_PER_DAY);
600 assert_se(format_timestamp_relative(buf, sizeof(buf), x));
601 log_debug("%s", buf);
602 ASSERT_STREQ(buf, "2 months 2 days ago");
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));
607 log_debug("%s", buf);
608 ASSERT_STREQ(buf, "1 week 1 day ago");
609
610 x = now(CLOCK_REALTIME) - (1*USEC_PER_WEEK + 2*USEC_PER_DAY);
611 assert_se(format_timestamp_relative(buf, sizeof(buf), x));
612 log_debug("%s", buf);
613 ASSERT_STREQ(buf, "1 week 2 days ago");
614
615 x = now(CLOCK_REALTIME) - (2*USEC_PER_WEEK + 1*USEC_PER_DAY);
616 assert_se(format_timestamp_relative(buf, sizeof(buf), x));
617 log_debug("%s", buf);
618 ASSERT_STREQ(buf, "2 weeks 1 day ago");
619
620 x = now(CLOCK_REALTIME) - (2*USEC_PER_WEEK + 2*USEC_PER_DAY);
621 assert_se(format_timestamp_relative(buf, sizeof(buf), x));
622 log_debug("%s", buf);
623 ASSERT_STREQ(buf, "2 weeks 2 days ago");
624 }
625
626 static void test_format_timestamp_one(usec_t val, TimestampStyle style, const char *result) {
627 char buf[FORMAT_TIMESTAMP_MAX];
628 const char *t;
629
630 t = format_timestamp_style(buf, sizeof(buf), val, style);
631 ASSERT_STREQ(t, result);
632 }
633
634 TEST(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");
646
647 #if SIZEOF_TIME_T == 8
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");
653 #elif SIZEOF_TIME_T == 4
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");
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");
659 #endif
660
661 test_format_timestamp_one(USEC_INFINITY, TIMESTAMP_UTC, NULL);
662 }
663
664 static void test_parse_timestamp_one(const char *str, usec_t max_diff, usec_t expected) {
665 usec_t usec = USEC_INFINITY;
666 int r;
667
668 r = parse_timestamp(str, &usec);
669 log_debug("/* %s(%s): max_diff="USEC_FMT", expected="USEC_FMT", result="USEC_FMT" */", __func__, str, max_diff, expected, usec);
670 assert_se(r >= 0);
671 assert_se(usec >= expected);
672 assert_se(usec_sub_unsigned(usec, expected) <= max_diff);
673 }
674
675 static 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
682 static 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
693 static void test_parse_timestamp_impl(const char *tz) {
694 usec_t today, today2, now_usec;
695
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
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
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);
728 assert_se(parse_timestamp("1937-01-01T12:00:27.87+00:20", NULL) == -ERANGE); /* we don't support pre-epoch timestamps */
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
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);
793 }
794
795 if (streq_ptr(tz, "Asia/Tokyo")) {
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);
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);
839 }
840
841 if (streq_ptr(tz, "America/New_York")) {
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);
862 }
863
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
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);
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 }
963
964 /* with timezone */
965 if (tz) {
966 _cleanup_free_ char *s = NULL;
967
968 ASSERT_NOT_NULL((s = strjoin("Fri 2012-11-23 23:02:15 ", tz)));
969 ASSERT_OK(parse_timestamp(s, NULL));
970 }
971
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
982 TEST(parse_timestamp) {
983 test_parse_timestamp_impl(NULL);
984 }
985
986 static 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
1007 TEST(parse_timestamp_with_tz) {
1008 _cleanup_strv_free_ char **timezones = NULL;
1009
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
1015 assert_se(get_timezones(&timezones) >= 0);
1016 STRV_FOREACH(tz, timezones)
1017 test_parse_timestamp_with_tz_one(*tz);
1018 }
1019
1020 TEST(deserialize_dual_timestamp) {
1021 int r;
1022 dual_timestamp t;
1023
1024 r = deserialize_dual_timestamp("1234 5678", &t);
1025 assert_se(r == 0);
1026 assert_se(t.realtime == 1234);
1027 assert_se(t.monotonic == 5678);
1028
1029 r = deserialize_dual_timestamp("1234x 5678", &t);
1030 assert_se(r == -EINVAL);
1031
1032 r = deserialize_dual_timestamp("1234 5678y", &t);
1033 assert_se(r == -EINVAL);
1034
1035 r = deserialize_dual_timestamp("-1234 5678", &t);
1036 assert_se(r == -EINVAL);
1037
1038 r = deserialize_dual_timestamp("1234 -5678", &t);
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
1045 r = deserialize_dual_timestamp("+123 567", &t);
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. */
1051 r = deserialize_dual_timestamp("18446744073709551617 0", &t);
1052 assert_se(r == 0);
1053 assert_se(t.realtime == USEC_INFINITY);
1054 assert_se(t.monotonic == 0);
1055 }
1056
1057 static 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
1065 assert_se(d < 10*USEC_PER_SEC);
1066 }
1067
1068 TEST(usec_shift_clock) {
1069 usec_t rt, mn, bt;
1070
1071 rt = now(CLOCK_REALTIME);
1072 mn = now(CLOCK_MONOTONIC);
1073 bt = now(CLOCK_BOOTTIME);
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);
1078 assert_similar(usec_shift_clock(rt + 2*USEC_PER_HOUR, CLOCK_REALTIME, CLOCK_BOOTTIME), bt + 2*USEC_PER_HOUR);
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);
1082 assert_similar(usec_shift_clock(mn + 5*USEC_PER_HOUR, CLOCK_MONOTONIC, CLOCK_BOOTTIME), bt + 5*USEC_PER_HOUR);
1083 assert_se(usec_shift_clock(mn + 6*USEC_PER_HOUR, CLOCK_MONOTONIC, CLOCK_MONOTONIC) == mn + 6*USEC_PER_HOUR);
1084
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);
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);
1091 assert_similar(usec_shift_clock(rt - 50 * USEC_PER_SEC, CLOCK_REALTIME, CLOCK_BOOTTIME), bt - 50 * USEC_PER_SEC);
1092 }
1093 }
1094
1095 TEST(in_utc_timezone) {
1096 const char *tz = getenv("TZ");
1097
1098 assert_se(setenv("TZ", ":UTC", 1) >= 0);
1099 assert_se(in_utc_timezone());
1100 ASSERT_STREQ(tzname[0], "UTC");
1101 ASSERT_STREQ(tzname[1], "UTC");
1102 assert_se(timezone == 0);
1103 assert_se(daylight == 0);
1104
1105 assert_se(setenv("TZ", ":Europe/Berlin", 1) >= 0);
1106 assert_se(!in_utc_timezone());
1107 ASSERT_STREQ(tzname[0], "CET");
1108 ASSERT_STREQ(tzname[1], "CEST");
1109
1110 assert_se(set_unset_env("TZ", tz, true) == 0);
1111 tzset();
1112 }
1113
1114 TEST(map_clock_usec) {
1115 usec_t nowr, x, y, z;
1116
1117 x = nowr = now(CLOCK_REALTIME); /* right now */
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);
1127 assert_se(timestamp_is_set(y));
1128 z = map_clock_usec(y, CLOCK_MONOTONIC, CLOCK_REALTIME);
1129 assert_se(timestamp_is_set(z));
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);
1138 assert_se(timestamp_is_set(z));
1139 assert_se((z > x ? z - x : x - z) < USEC_PER_HOUR);
1140 }
1141 }
1142
1143 static 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);
1152 ASSERT_STREQ(s, utc);
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);
1159 ASSERT_STREQ(s, pretty);
1160 assert_se(x == y);
1161 assert_se(x == z);
1162 }
1163
1164 TEST(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
1208 static usec_t absdiff(usec_t a, usec_t b) {
1209 return a > b ? a - b : b - a;
1210 }
1211
1212 TEST(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
1235 static int intro(void) {
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
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),
1244 now(CLOCK_BOOTTIME));
1245
1246 /* Ensure time_t is signed */
1247 assert_cc((time_t) -1 < (time_t) 1);
1248
1249 /* Ensure TIME_T_MAX works correctly */
1250 uintmax_t x = TIME_T_MAX;
1251 x++;
1252 assert_se((time_t) x < 0);
1253
1254 return EXIT_SUCCESS;
1255 }
1256
1257 DEFINE_TEST_MAIN_WITH_INTRO(LOG_INFO, intro);