• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

systemd / systemd / 13380515387

17 Feb 2025 09:20PM UTC coverage: 71.822% (+0.1%) from 71.714%
13380515387

push

github

DaanDeMeyer
ukify: print all remaining log-like output to stderr

We want to be able to capture stdout for json and such, so convert
all remaining logging to stderr.

293883 of 409184 relevant lines covered (71.82%)

716959.33 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.64
/src/test/test-time-util.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#include "env-util.h"
4
#include "fd-util.h"
5
#include "fileio.h"
6
#include "random-util.h"
7
#include "serialize.h"
8
#include "string-util.h"
9
#include "strv.h"
10
#include "tests.h"
11
#include "time-util.h"
12

13
#define TRIAL 100u
14

15
TEST(parse_sec) {
1✔
16
        usec_t u;
1✔
17

18
        assert_se(parse_sec("5s", &u) >= 0);
1✔
19
        assert_se(u == 5 * USEC_PER_SEC);
1✔
20
        assert_se(parse_sec("5s500ms", &u) >= 0);
1✔
21
        assert_se(u == 5 * USEC_PER_SEC + 500 * USEC_PER_MSEC);
1✔
22
        assert_se(parse_sec(" 5s 500ms  ", &u) >= 0);
1✔
23
        assert_se(u == 5 * USEC_PER_SEC + 500 * USEC_PER_MSEC);
1✔
24
        assert_se(parse_sec(" 5.5s  ", &u) >= 0);
1✔
25
        assert_se(u == 5 * USEC_PER_SEC + 500 * USEC_PER_MSEC);
1✔
26
        assert_se(parse_sec(" 5.5s 0.5ms ", &u) >= 0);
1✔
27
        assert_se(u == 5 * USEC_PER_SEC + 500 * USEC_PER_MSEC + 500);
1✔
28
        assert_se(parse_sec(" .22s ", &u) >= 0);
1✔
29
        assert_se(u == 220 * USEC_PER_MSEC);
1✔
30
        assert_se(parse_sec(" .50y ", &u) >= 0);
1✔
31
        assert_se(u == USEC_PER_YEAR / 2);
1✔
32
        assert_se(parse_sec("2.5", &u) >= 0);
1✔
33
        assert_se(u == 2500 * USEC_PER_MSEC);
1✔
34
        assert_se(parse_sec(".7", &u) >= 0);
1✔
35
        assert_se(u == 700 * USEC_PER_MSEC);
1✔
36
        assert_se(parse_sec("23us", &u) >= 0);
1✔
37
        assert_se(u == 23);
1✔
38
        assert_se(parse_sec("23μs", &u) >= 0); /* greek small letter mu */
1✔
39
        assert_se(u == 23);
1✔
40
        assert_se(parse_sec("23µs", &u) >= 0); /* micro symbol */
1✔
41
        assert_se(u == 23);
1✔
42
        assert_se(parse_sec("infinity", &u) >= 0);
1✔
43
        assert_se(u == USEC_INFINITY);
1✔
44
        assert_se(parse_sec(" infinity ", &u) >= 0);
1✔
45
        assert_se(u == USEC_INFINITY);
1✔
46
        assert_se(parse_sec("+3.1s", &u) >= 0);
1✔
47
        assert_se(u == 3100 * USEC_PER_MSEC);
1✔
48
        assert_se(parse_sec("3.1s.2", &u) >= 0);
1✔
49
        assert_se(u == 3300 * USEC_PER_MSEC);
1✔
50
        assert_se(parse_sec("3.1 .2", &u) >= 0);
1✔
51
        assert_se(u == 3300 * USEC_PER_MSEC);
1✔
52
        assert_se(parse_sec("3.1 sec .2 sec", &u) >= 0);
1✔
53
        assert_se(u == 3300 * USEC_PER_MSEC);
1✔
54
        assert_se(parse_sec("3.1 sec 1.2 sec", &u) >= 0);
1✔
55
        assert_se(u == 4300 * USEC_PER_MSEC);
1✔
56

57
        assert_se(parse_sec(" xyz ", &u) < 0);
1✔
58
        assert_se(parse_sec("", &u) < 0);
1✔
59
        assert_se(parse_sec(" . ", &u) < 0);
1✔
60
        assert_se(parse_sec(" 5. ", &u) < 0);
1✔
61
        assert_se(parse_sec(".s ", &u) < 0);
1✔
62
        assert_se(parse_sec("-5s ", &u) < 0);
1✔
63
        assert_se(parse_sec("-0.3s ", &u) < 0);
1✔
64
        assert_se(parse_sec("-0.0s ", &u) < 0);
1✔
65
        assert_se(parse_sec("-0.-0s ", &u) < 0);
1✔
66
        assert_se(parse_sec("0.-0s ", &u) < 0);
1✔
67
        assert_se(parse_sec("3.-0s ", &u) < 0);
1✔
68
        assert_se(parse_sec(" infinity .7", &u) < 0);
1✔
69
        assert_se(parse_sec(".3 infinity", &u) < 0);
1✔
70
        assert_se(parse_sec("3.+1s", &u) < 0);
1✔
71
        assert_se(parse_sec("3. 1s", &u) < 0);
1✔
72
        assert_se(parse_sec("3.s", &u) < 0);
1✔
73
        assert_se(parse_sec("12.34.56", &u) < 0);
1✔
74
        assert_se(parse_sec("12..34", &u) < 0);
1✔
75
        assert_se(parse_sec("..1234", &u) < 0);
1✔
76
        assert_se(parse_sec("1234..", &u) < 0);
1✔
77
}
1✔
78

79
TEST(parse_sec_fix_0) {
1✔
80
        usec_t u;
1✔
81

82
        assert_se(parse_sec_fix_0("5s", &u) >= 0);
1✔
83
        assert_se(u == 5 * USEC_PER_SEC);
1✔
84
        assert_se(parse_sec_fix_0("0s", &u) >= 0);
1✔
85
        assert_se(u == USEC_INFINITY);
1✔
86
        assert_se(parse_sec_fix_0("0", &u) >= 0);
1✔
87
        assert_se(u == USEC_INFINITY);
1✔
88
        assert_se(parse_sec_fix_0(" 0", &u) >= 0);
1✔
89
        assert_se(u == USEC_INFINITY);
1✔
90
}
1✔
91

92
TEST(parse_sec_def_infinity) {
1✔
93
        usec_t u;
1✔
94

95
        assert_se(parse_sec_def_infinity("5s", &u) >= 0);
1✔
96
        assert_se(u == 5 * USEC_PER_SEC);
1✔
97
        assert_se(parse_sec_def_infinity("", &u) >= 0);
1✔
98
        assert_se(u == USEC_INFINITY);
1✔
99
        assert_se(parse_sec_def_infinity("     ", &u) >= 0);
1✔
100
        assert_se(u == USEC_INFINITY);
1✔
101
        assert_se(parse_sec_def_infinity("0s", &u) >= 0);
1✔
102
        assert_se(u == 0);
1✔
103
        assert_se(parse_sec_def_infinity("0", &u) >= 0);
1✔
104
        assert_se(u == 0);
1✔
105
        assert_se(parse_sec_def_infinity(" 0", &u) >= 0);
1✔
106
        assert_se(u == 0);
1✔
107
        assert_se(parse_sec_def_infinity("-5s", &u) < 0);
1✔
108
}
1✔
109

110
TEST(parse_time) {
1✔
111
        usec_t u;
1✔
112

113
        assert_se(parse_time("5", &u, 1) >= 0);
1✔
114
        assert_se(u == 5);
1✔
115

116
        assert_se(parse_time("5", &u, USEC_PER_MSEC) >= 0);
1✔
117
        assert_se(u == 5 * USEC_PER_MSEC);
1✔
118

119
        assert_se(parse_time("5", &u, USEC_PER_SEC) >= 0);
1✔
120
        assert_se(u == 5 * USEC_PER_SEC);
1✔
121

122
        assert_se(parse_time("5s", &u, 1) >= 0);
1✔
123
        assert_se(u == 5 * USEC_PER_SEC);
1✔
124

125
        assert_se(parse_time("5s", &u, USEC_PER_SEC) >= 0);
1✔
126
        assert_se(u == 5 * USEC_PER_SEC);
1✔
127

128
        assert_se(parse_time("5s", &u, USEC_PER_MSEC) >= 0);
1✔
129
        assert_se(u == 5 * USEC_PER_SEC);
1✔
130

131
        assert_se(parse_time("11111111111111y", &u, 1) == -ERANGE);
1✔
132
        assert_se(parse_time("1.1111111111111y", &u, 1) >= 0);
1✔
133
}
1✔
134

135
TEST(parse_nsec) {
1✔
136
        nsec_t u;
1✔
137

138
        assert_se(parse_nsec("5s", &u) >= 0);
1✔
139
        assert_se(u == 5 * NSEC_PER_SEC);
1✔
140
        assert_se(parse_nsec("5s500ms", &u) >= 0);
1✔
141
        assert_se(u == 5 * NSEC_PER_SEC + 500 * NSEC_PER_MSEC);
1✔
142
        assert_se(parse_nsec(" 5s 500ms  ", &u) >= 0);
1✔
143
        assert_se(u == 5 * NSEC_PER_SEC + 500 * NSEC_PER_MSEC);
1✔
144
        assert_se(parse_nsec(" 5.5s  ", &u) >= 0);
1✔
145
        assert_se(u == 5 * NSEC_PER_SEC + 500 * NSEC_PER_MSEC);
1✔
146
        assert_se(parse_nsec(" 5.5s 0.5ms ", &u) >= 0);
1✔
147
        assert_se(u == 5 * NSEC_PER_SEC + 500 * NSEC_PER_MSEC + 500 * NSEC_PER_USEC);
1✔
148
        assert_se(parse_nsec(" .22s ", &u) >= 0);
1✔
149
        assert_se(u == 220 * NSEC_PER_MSEC);
1✔
150
        assert_se(parse_nsec(" .50y ", &u) >= 0);
1✔
151
        assert_se(u == NSEC_PER_YEAR / 2);
1✔
152
        assert_se(parse_nsec("2.5", &u) >= 0);
1✔
153
        assert_se(u == 2);
1✔
154
        assert_se(parse_nsec(".7", &u) >= 0);
1✔
155
        assert_se(u == 0);
1✔
156
        assert_se(parse_nsec("infinity", &u) >= 0);
1✔
157
        assert_se(u == NSEC_INFINITY);
1✔
158
        assert_se(parse_nsec(" infinity ", &u) >= 0);
1✔
159
        assert_se(u == NSEC_INFINITY);
1✔
160
        assert_se(parse_nsec("+3.1s", &u) >= 0);
1✔
161
        assert_se(u == 3100 * NSEC_PER_MSEC);
1✔
162
        assert_se(parse_nsec("3.1s.2", &u) >= 0);
1✔
163
        assert_se(u == 3100 * NSEC_PER_MSEC);
1✔
164
        assert_se(parse_nsec("3.1 .2s", &u) >= 0);
1✔
165
        assert_se(u == 200 * NSEC_PER_MSEC + 3);
1✔
166
        assert_se(parse_nsec("3.1 sec .2 sec", &u) >= 0);
1✔
167
        assert_se(u == 3300 * NSEC_PER_MSEC);
1✔
168
        assert_se(parse_nsec("3.1 sec 1.2 sec", &u) >= 0);
1✔
169
        assert_se(u == 4300 * NSEC_PER_MSEC);
1✔
170

171
        assert_se(parse_nsec(" xyz ", &u) < 0);
1✔
172
        assert_se(parse_nsec("", &u) < 0);
1✔
173
        assert_se(parse_nsec(" . ", &u) < 0);
1✔
174
        assert_se(parse_nsec(" 5. ", &u) < 0);
1✔
175
        assert_se(parse_nsec(".s ", &u) < 0);
1✔
176
        assert_se(parse_nsec(" infinity .7", &u) < 0);
1✔
177
        assert_se(parse_nsec(".3 infinity", &u) < 0);
1✔
178
        assert_se(parse_nsec("-5s ", &u) < 0);
1✔
179
        assert_se(parse_nsec("-0.3s ", &u) < 0);
1✔
180
        assert_se(parse_nsec("-0.0s ", &u) < 0);
1✔
181
        assert_se(parse_nsec("-0.-0s ", &u) < 0);
1✔
182
        assert_se(parse_nsec("0.-0s ", &u) < 0);
1✔
183
        assert_se(parse_nsec("3.-0s ", &u) < 0);
1✔
184
        assert_se(parse_nsec(" infinity .7", &u) < 0);
1✔
185
        assert_se(parse_nsec(".3 infinity", &u) < 0);
1✔
186
        assert_se(parse_nsec("3.+1s", &u) < 0);
1✔
187
        assert_se(parse_nsec("3. 1s", &u) < 0);
1✔
188
        assert_se(parse_nsec("3.s", &u) < 0);
1✔
189
        assert_se(parse_nsec("12.34.56", &u) < 0);
1✔
190
        assert_se(parse_nsec("12..34", &u) < 0);
1✔
191
        assert_se(parse_nsec("..1234", &u) < 0);
1✔
192
        assert_se(parse_nsec("1234..", &u) < 0);
1✔
193
        assert_se(parse_nsec("1111111111111y", &u) == -ERANGE);
1✔
194
        assert_se(parse_nsec("1.111111111111y", &u) >= 0);
1✔
195
}
1✔
196

197
static void test_format_timespan_one(usec_t x, usec_t accuracy) {
66✔
198
        char l[FORMAT_TIMESPAN_MAX];
66✔
199
        const char *t;
66✔
200
        usec_t y;
66✔
201

202
        log_debug(USEC_FMT"     (at accuracy "USEC_FMT")", x, accuracy);
66✔
203

204
        assert_se(t = format_timespan(l, sizeof l, x, accuracy));
66✔
205
        log_debug(" = <%s>", t);
66✔
206

207
        assert_se(parse_sec(t, &y) >= 0);
66✔
208
        log_debug(" = "USEC_FMT, y);
66✔
209

210
        if (accuracy <= 0)
66✔
211
                accuracy = 1;
×
212

213
        assert_se(x / accuracy == y / accuracy);
66✔
214
}
66✔
215

216
static void test_format_timespan_accuracy(usec_t accuracy) {
3✔
217
        log_info("/* %s accuracy="USEC_FMT" */", __func__, accuracy);
3✔
218

219
        test_format_timespan_one(0, accuracy);
3✔
220
        test_format_timespan_one(1, accuracy);
3✔
221
        test_format_timespan_one(1*USEC_PER_SEC, accuracy);
3✔
222
        test_format_timespan_one(999*USEC_PER_MSEC, accuracy);
3✔
223
        test_format_timespan_one(1234567, accuracy);
3✔
224
        test_format_timespan_one(12, accuracy);
3✔
225
        test_format_timespan_one(123, accuracy);
3✔
226
        test_format_timespan_one(1234, accuracy);
3✔
227
        test_format_timespan_one(12345, accuracy);
3✔
228
        test_format_timespan_one(123456, accuracy);
3✔
229
        test_format_timespan_one(1234567, accuracy);
3✔
230
        test_format_timespan_one(12345678, accuracy);
3✔
231
        test_format_timespan_one(1200000, accuracy);
3✔
232
        test_format_timespan_one(1230000, accuracy);
3✔
233
        test_format_timespan_one(1234000, accuracy);
3✔
234
        test_format_timespan_one(1234500, accuracy);
3✔
235
        test_format_timespan_one(1234560, accuracy);
3✔
236
        test_format_timespan_one(1234567, accuracy);
3✔
237
        test_format_timespan_one(986087, accuracy);
3✔
238
        test_format_timespan_one(500 * USEC_PER_MSEC, accuracy);
3✔
239
        test_format_timespan_one(9*USEC_PER_YEAR/5 - 23, accuracy);
3✔
240
        test_format_timespan_one(USEC_INFINITY, accuracy);
3✔
241
}
3✔
242

243
TEST(format_timespan) {
1✔
244
        test_format_timespan_accuracy(1);
1✔
245
        test_format_timespan_accuracy(USEC_PER_MSEC);
1✔
246
        test_format_timespan_accuracy(USEC_PER_SEC);
1✔
247

248
        /* See issue #23928. */
249
        _cleanup_free_ char *buf = NULL;
2✔
250
        assert_se(buf = new(char, 5));
1✔
251
        assert_se(buf == format_timespan(buf, 5, 100005, 1000));
1✔
252
}
1✔
253

254
TEST(verify_timezone) {
1✔
255
        assert_se(verify_timezone("Europe/Berlin", LOG_DEBUG) == 0);
1✔
256
        assert_se(verify_timezone("Australia/Sydney", LOG_DEBUG) == 0);
1✔
257
        assert_se(verify_timezone("Europe/Do not exist", LOG_DEBUG) == -EINVAL);
1✔
258
        assert_se(verify_timezone("Europe/DoNotExist", LOG_DEBUG) == -ENOENT);
1✔
259
        assert_se(verify_timezone("/DoNotExist", LOG_DEBUG) == -EINVAL);
1✔
260
        assert_se(verify_timezone("DoNotExist/", LOG_DEBUG) == -EINVAL);
1✔
261
}
1✔
262

263
TEST(timezone_is_valid) {
1✔
264
        assert_se(timezone_is_valid("Europe/Berlin", LOG_ERR));
1✔
265
        assert_se(timezone_is_valid("Australia/Sydney", LOG_ERR));
1✔
266
        assert_se(!timezone_is_valid("Europe/Do not exist", LOG_ERR));
1✔
267
}
1✔
268

269
TEST(get_timezones) {
1✔
270
        _cleanup_strv_free_ char **zones = NULL;
1✔
271
        int r;
1✔
272

273
        r = get_timezones(&zones);
1✔
274
        assert_se(r == 0);
1✔
275

276
        STRV_FOREACH(zone, zones) {
598✔
277
                r = verify_timezone(*zone, LOG_ERR);
597✔
278
                log_debug_errno(r, "verify_timezone(\"%s\"): %m", *zone);
597✔
279
                assert_se(r >= 0 || r == -ENOENT);
597✔
280
        }
281
}
1✔
282

283
TEST(usec_add) {
1✔
284
        assert_se(usec_add(0, 0) == 0);
1✔
285
        assert_se(usec_add(1, 4) == 5);
1✔
286
        assert_se(usec_add(USEC_INFINITY, 5) == USEC_INFINITY);
1✔
287
        assert_se(usec_add(5, USEC_INFINITY) == USEC_INFINITY);
1✔
288
        assert_se(usec_add(USEC_INFINITY-5, 2) == USEC_INFINITY-3);
1✔
289
        assert_se(usec_add(USEC_INFINITY-2, 2) == USEC_INFINITY);
1✔
290
        assert_se(usec_add(USEC_INFINITY-1, 2) == USEC_INFINITY);
1✔
291
        assert_se(usec_add(USEC_INFINITY, 2) == USEC_INFINITY);
1✔
292
}
1✔
293

294
TEST(usec_sub_unsigned) {
1✔
295
        assert_se(usec_sub_unsigned(0, 0) == 0);
1✔
296
        assert_se(usec_sub_unsigned(0, 2) == 0);
1✔
297
        assert_se(usec_sub_unsigned(0, USEC_INFINITY) == 0);
1✔
298
        assert_se(usec_sub_unsigned(1, 0) == 1);
1✔
299
        assert_se(usec_sub_unsigned(1, 1) == 0);
1✔
300
        assert_se(usec_sub_unsigned(1, 2) == 0);
1✔
301
        assert_se(usec_sub_unsigned(1, 3) == 0);
1✔
302
        assert_se(usec_sub_unsigned(1, USEC_INFINITY) == 0);
1✔
303
        assert_se(usec_sub_unsigned(USEC_INFINITY-1, 0) == USEC_INFINITY-1);
1✔
304
        assert_se(usec_sub_unsigned(USEC_INFINITY-1, 1) == USEC_INFINITY-2);
1✔
305
        assert_se(usec_sub_unsigned(USEC_INFINITY-1, 2) == USEC_INFINITY-3);
1✔
306
        assert_se(usec_sub_unsigned(USEC_INFINITY-1, USEC_INFINITY-2) == 1);
1✔
307
        assert_se(usec_sub_unsigned(USEC_INFINITY-1, USEC_INFINITY-1) == 0);
1✔
308
        assert_se(usec_sub_unsigned(USEC_INFINITY-1, USEC_INFINITY) == 0);
1✔
309
        assert_se(usec_sub_unsigned(USEC_INFINITY, 0) == USEC_INFINITY);
1✔
310
        assert_se(usec_sub_unsigned(USEC_INFINITY, 1) == USEC_INFINITY);
1✔
311
        assert_se(usec_sub_unsigned(USEC_INFINITY, 2) == USEC_INFINITY);
1✔
312
        assert_se(usec_sub_unsigned(USEC_INFINITY, USEC_INFINITY) == USEC_INFINITY);
1✔
313
}
1✔
314

315
TEST(usec_sub_signed) {
1✔
316
        assert_se(usec_sub_signed(0, 0) == 0);
1✔
317
        assert_se(usec_sub_signed(4, 1) == 3);
1✔
318
        assert_se(usec_sub_signed(4, 4) == 0);
1✔
319
        assert_se(usec_sub_signed(4, 5) == 0);
1✔
320

321
        assert_se(usec_sub_signed(USEC_INFINITY-3, -3) == USEC_INFINITY);
1✔
322
        assert_se(usec_sub_signed(USEC_INFINITY-3, -4) == USEC_INFINITY);
1✔
323
        assert_se(usec_sub_signed(USEC_INFINITY-3, -5) == USEC_INFINITY);
1✔
324
        assert_se(usec_sub_signed(USEC_INFINITY, 5) == USEC_INFINITY);
1✔
325

326
        assert_se(usec_sub_signed(0, INT64_MAX) == 0);
1✔
327
        assert_se(usec_sub_signed(0, -INT64_MAX) == INT64_MAX);
1✔
328
        assert_se(usec_sub_signed(0, INT64_MIN) == (usec_t) INT64_MAX + 1);
1✔
329
        assert_se(usec_sub_signed(0, -(INT64_MIN+1)) == 0);
1✔
330

331
        assert_se(usec_sub_signed(USEC_INFINITY, INT64_MAX) == USEC_INFINITY);
1✔
332
        assert_se(usec_sub_signed(USEC_INFINITY, -INT64_MAX) == USEC_INFINITY);
1✔
333
        assert_se(usec_sub_signed(USEC_INFINITY, INT64_MIN) == USEC_INFINITY);
1✔
334
        assert_se(usec_sub_signed(USEC_INFINITY, -(INT64_MIN+1)) == USEC_INFINITY);
1✔
335

336
        assert_se(usec_sub_signed(USEC_INFINITY-1, INT64_MAX) == USEC_INFINITY-1-INT64_MAX);
1✔
337
        assert_se(usec_sub_signed(USEC_INFINITY-1, -INT64_MAX) == USEC_INFINITY);
1✔
338
        assert_se(usec_sub_signed(USEC_INFINITY-1, INT64_MIN) == USEC_INFINITY);
1✔
339
        assert_se(usec_sub_signed(USEC_INFINITY-1, -(INT64_MIN+1)) == USEC_INFINITY-1-((usec_t) (-(INT64_MIN+1))));
1✔
340
}
1✔
341

342
TEST(format_timestamp) {
1✔
343
        for (unsigned i = 0; i < TRIAL; i++) {
101✔
344
                char buf[CONST_MAX(FORMAT_TIMESTAMP_MAX, FORMAT_TIMESPAN_MAX)];
100✔
345
                usec_t x, y;
100✔
346

347
                x = random_u64_range(USEC_TIMESTAMP_FORMATTABLE_MAX - USEC_PER_SEC) + USEC_PER_SEC;
100✔
348

349
                assert_se(format_timestamp(buf, sizeof(buf), x));
100✔
350
                log_debug("%s", buf);
100✔
351
                assert_se(parse_timestamp(buf, &y) >= 0);
100✔
352
                assert_se(x / USEC_PER_SEC == y / USEC_PER_SEC);
100✔
353

354
                assert_se(format_timestamp_style(buf, sizeof(buf), x, TIMESTAMP_UNIX));
100✔
355
                log_debug("%s", buf);
100✔
356
                assert_se(parse_timestamp(buf, &y) >= 0);
100✔
357
                assert_se(x / USEC_PER_SEC == y / USEC_PER_SEC);
100✔
358

359
                assert_se(format_timestamp_style(buf, sizeof(buf), x, TIMESTAMP_UTC));
100✔
360
                log_debug("%s", buf);
100✔
361
                assert_se(parse_timestamp(buf, &y) >= 0);
100✔
362
                assert_se(x / USEC_PER_SEC == y / USEC_PER_SEC);
100✔
363

364
                assert_se(format_timestamp_style(buf, sizeof(buf), x, TIMESTAMP_US));
100✔
365
                log_debug("%s", buf);
100✔
366
                assert_se(parse_timestamp(buf, &y) >= 0);
100✔
367
                assert_se(x == y);
100✔
368

369
                assert_se(format_timestamp_style(buf, sizeof(buf), x, TIMESTAMP_US_UTC));
100✔
370
                log_debug("%s", buf);
100✔
371
                assert_se(parse_timestamp(buf, &y) >= 0);
100✔
372
                assert_se(x == y);
100✔
373

374
                if (x > 2 * USEC_PER_DAY) {
100✔
375
                        assert_se(format_timestamp_style(buf, sizeof(buf), x, TIMESTAMP_DATE));
100✔
376
                        log_debug("%s", buf);
100✔
377
                        assert_se(parse_timestamp(buf, &y) >= 0);
100✔
378
                        assert_se(y > usec_sub_unsigned(x, 2 * USEC_PER_DAY) && y < usec_add(x, 2 * USEC_PER_DAY));
300✔
379
                }
380

381
                assert_se(format_timestamp_relative(buf, sizeof(buf), x));
100✔
382
                log_debug("%s", buf);
100✔
383
                assert_se(parse_timestamp(buf, &y) >= 0);
100✔
384

385
                /* The two calls above will run with a slightly different local time. Make sure we are in the same
386
                 * range however, but give enough leeway that this is unlikely to explode. And of course,
387
                 * format_timestamp_relative() scales the accuracy with the distance from the current time up to one
388
                 * month, cover for that too. */
389
                assert_se(y > x ? y - x : x - y <= USEC_PER_MONTH + USEC_PER_DAY);
100✔
390
        }
391
}
1✔
392

393
static void test_format_timestamp_impl(usec_t x) {
214✔
394
        bool success, override;
214✔
395
        const char *xx, *yy;
214✔
396
        usec_t y, x_sec, y_sec;
214✔
397

398
        xx = FORMAT_TIMESTAMP(x);
214✔
399
        ASSERT_NOT_NULL(xx);
214✔
400
        ASSERT_OK(parse_timestamp(xx, &y));
214✔
401
        yy = FORMAT_TIMESTAMP(y);
214✔
402
        ASSERT_NOT_NULL(yy);
214✔
403

404
        x_sec = x / USEC_PER_SEC;
214✔
405
        y_sec = y / USEC_PER_SEC;
214✔
406
        success = (x_sec == y_sec) && streq(xx, yy);
214✔
407
        /* Workaround for https://github.com/systemd/systemd/issues/28472
408
         * and https://github.com/systemd/systemd/pull/35471. */
409
        override = !success &&
214✔
410
                   (STRPTR_IN_SET(tzname[0], "CAT", "EAT", "WET") ||
×
411
                    STRPTR_IN_SET(tzname[1], "CAT", "EAT", "WET")) &&
×
412
                   (x_sec > y_sec ? x_sec - y_sec : y_sec - x_sec) == 3600; /* 1 hour, ignore fractional second */
×
413
        log_full(success ? LOG_DEBUG : override ? LOG_WARNING : LOG_ERR,
428✔
414
                 "@" USEC_FMT " → %s → @" USEC_FMT " → %s%s",
415
                 x, xx, y, yy,
416
                 override ? ", ignoring." : "");
417
        if (!override) {
214✔
418
                if (!success)
214✔
419
                        log_warning("tzname[0]=\"%s\", tzname[1]=\"%s\"", tzname[0], tzname[1]);
×
420
                ASSERT_EQ(x_sec, y_sec);
214✔
421
                ASSERT_STREQ(xx, yy);
214✔
422
        }
423
}
214✔
424

425
static void test_format_timestamp_loop(void) {
2✔
426
        test_format_timestamp_impl(USEC_PER_DAY + USEC_PER_SEC);
2✔
427
        test_format_timestamp_impl(USEC_TIMESTAMP_FORMATTABLE_MAX_32BIT-1);
2✔
428
        test_format_timestamp_impl(USEC_TIMESTAMP_FORMATTABLE_MAX_32BIT);
2✔
429
        test_format_timestamp_impl(USEC_TIMESTAMP_FORMATTABLE_MAX-1);
2✔
430
        test_format_timestamp_impl(USEC_TIMESTAMP_FORMATTABLE_MAX);
2✔
431

432
        /* Two cases which trigger https://github.com/systemd/systemd/issues/28472 */
433
        test_format_timestamp_impl(1504938962980066);
2✔
434
        test_format_timestamp_impl(1509482094632752);
2✔
435

436
        for (unsigned i = 0; i < TRIAL; i++) {
202✔
437
                usec_t x;
200✔
438

439
                x = random_u64_range(USEC_TIMESTAMP_FORMATTABLE_MAX - USEC_PER_SEC) + USEC_PER_SEC;
200✔
440
                test_format_timestamp_impl(x);
200✔
441
        }
442
}
2✔
443

444
TEST(FORMAT_TIMESTAMP) {
1✔
445
        test_format_timestamp_loop();
1✔
446
}
1✔
447

448
static void test_format_timestamp_with_tz_one(const char *tz) {
1✔
449
        const char *saved_tz, *colon_tz;
1✔
450

451
        if (!timezone_is_valid(tz, LOG_DEBUG))
1✔
452
                return;
453

454
        log_info("/* %s(%s) */", __func__, tz);
1✔
455

456
        saved_tz = getenv("TZ");
1✔
457

458
        assert_se(colon_tz = strjoina(":", tz));
5✔
459
        assert_se(setenv("TZ", colon_tz, 1) >= 0);
1✔
460
        tzset();
1✔
461
        log_debug("%s: tzname[0]=%s, tzname[1]=%s", tz, strempty(tzname[0]), strempty(tzname[1]));
1✔
462

463
        test_format_timestamp_loop();
1✔
464

465
        assert_se(set_unset_env("TZ", saved_tz, true) == 0);
1✔
466
        tzset();
1✔
467
}
468

469
TEST(FORMAT_TIMESTAMP_with_tz) {
1✔
470
        _cleanup_strv_free_ char **timezones = NULL;
×
471

472
        test_format_timestamp_with_tz_one("UTC");
1✔
473

474
        if (!slow_tests_enabled())
1✔
475
                return (void) log_tests_skipped("slow tests are disabled");
1✔
476

477
        assert_se(get_timezones(&timezones) >= 0);
×
478
        STRV_FOREACH(tz, timezones)
×
479
                test_format_timestamp_with_tz_one(*tz);
×
480
}
481

482
TEST(format_timestamp_relative_full) {
1✔
483
        char buf[CONST_MAX(FORMAT_TIMESTAMP_MAX, FORMAT_TIMESPAN_MAX)];
1✔
484
        usec_t x;
1✔
485

486
        /* Years and months */
487
        x = now(CLOCK_REALTIME) - (1*USEC_PER_YEAR + 1*USEC_PER_MONTH);
1✔
488
        assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_REALTIME, true));
1✔
489
        log_debug("%s", buf);
1✔
490
        ASSERT_STREQ(buf, "1 year 1 month ago");
1✔
491

492
        x = now(CLOCK_MONOTONIC) + (1*USEC_PER_YEAR + 1.5*USEC_PER_MONTH);
1✔
493
        assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_MONOTONIC, false));
1✔
494
        log_debug("%s", buf);
1✔
495
        ASSERT_STREQ(buf, "1 year 1 month left");
1✔
496

497
        x = now(CLOCK_REALTIME) - (1*USEC_PER_YEAR + 2*USEC_PER_MONTH);
1✔
498
        assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_REALTIME, true));
1✔
499
        log_debug("%s", buf);
1✔
500
        ASSERT_STREQ(buf, "1 year 2 months ago");
1✔
501

502
        x = now(CLOCK_REALTIME) - (2*USEC_PER_YEAR + 1*USEC_PER_MONTH);
1✔
503
        assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_REALTIME, true));
1✔
504
        log_debug("%s", buf);
1✔
505
        ASSERT_STREQ(buf, "2 years 1 month ago");
1✔
506

507
        x = now(CLOCK_REALTIME) - (2*USEC_PER_YEAR + 2*USEC_PER_MONTH);
1✔
508
        assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_REALTIME, true));
1✔
509
        log_debug("%s", buf);
1✔
510
        ASSERT_STREQ(buf, "2 years 2 months ago");
1✔
511

512
        /* Months and days */
513
        x = now(CLOCK_REALTIME) - (1*USEC_PER_MONTH + 1*USEC_PER_DAY);
1✔
514
        assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_REALTIME, true));
1✔
515
        log_debug("%s", buf);
1✔
516
        ASSERT_STREQ(buf, "1 month 1 day ago");
1✔
517

518
        x = now(CLOCK_REALTIME) - (1*USEC_PER_MONTH + 2*USEC_PER_DAY);
1✔
519
        assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_REALTIME, true));
1✔
520
        log_debug("%s", buf);
1✔
521
        ASSERT_STREQ(buf, "1 month 2 days ago");
1✔
522

523
        x = now(CLOCK_REALTIME) - (2*USEC_PER_MONTH + 1*USEC_PER_DAY);
1✔
524
        assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_REALTIME, true));
1✔
525
        log_debug("%s", buf);
1✔
526
        ASSERT_STREQ(buf, "2 months 1 day ago");
1✔
527

528
        x = now(CLOCK_REALTIME) - (2*USEC_PER_MONTH + 2*USEC_PER_DAY);
1✔
529
        assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_REALTIME, true));
1✔
530
        log_debug("%s", buf);
1✔
531
        ASSERT_STREQ(buf, "2 months 2 days ago");
1✔
532

533
        /* Weeks and days */
534
        x = now(CLOCK_REALTIME) - (1*USEC_PER_WEEK + 1*USEC_PER_DAY);
1✔
535
        assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_REALTIME, true));
1✔
536
        log_debug("%s", buf);
1✔
537
        ASSERT_STREQ(buf, "1 week 1 day ago");
1✔
538

539
        x = now(CLOCK_REALTIME) - (1*USEC_PER_WEEK + 2*USEC_PER_DAY);
1✔
540
        assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_REALTIME, true));
1✔
541
        log_debug("%s", buf);
1✔
542
        ASSERT_STREQ(buf, "1 week 2 days ago");
1✔
543

544
        x = now(CLOCK_REALTIME) - (2*USEC_PER_WEEK + 1*USEC_PER_DAY);
1✔
545
        assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_REALTIME, true));
1✔
546
        log_debug("%s", buf);
1✔
547
        ASSERT_STREQ(buf, "2 weeks 1 day ago");
1✔
548

549
        x = now(CLOCK_REALTIME) - (2*USEC_PER_WEEK + 2*USEC_PER_DAY);
1✔
550
        assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_REALTIME, true));
1✔
551
        log_debug("%s", buf);
1✔
552
        ASSERT_STREQ(buf, "2 weeks 2 days ago");
1✔
553
}
1✔
554

555
TEST(format_timestamp_relative) {
1✔
556
        char buf[CONST_MAX(FORMAT_TIMESTAMP_MAX, FORMAT_TIMESPAN_MAX)];
1✔
557
        usec_t x;
1✔
558

559
        /* Only testing timestamps in the past so we don't need to add some delta to account for time passing
560
         * by while we are running the tests (unless we're running on potatoes and 24 hours somehow passes
561
         * between our call to now() and format_timestamp_relative's call to now()). */
562

563
        /* Years and months */
564
        x = now(CLOCK_REALTIME) - (1*USEC_PER_YEAR + 1*USEC_PER_MONTH);
1✔
565
        assert_se(format_timestamp_relative(buf, sizeof(buf), x));
1✔
566
        log_debug("%s", buf);
1✔
567
        ASSERT_STREQ(buf, "1 year 1 month ago");
1✔
568

569
        x = now(CLOCK_REALTIME) - (1*USEC_PER_YEAR + 2*USEC_PER_MONTH);
1✔
570
        assert_se(format_timestamp_relative(buf, sizeof(buf), x));
1✔
571
        log_debug("%s", buf);
1✔
572
        ASSERT_STREQ(buf, "1 year 2 months ago");
1✔
573

574
        x = now(CLOCK_REALTIME) - (2*USEC_PER_YEAR + 1*USEC_PER_MONTH);
1✔
575
        assert_se(format_timestamp_relative(buf, sizeof(buf), x));
1✔
576
        log_debug("%s", buf);
1✔
577
        ASSERT_STREQ(buf, "2 years 1 month ago");
1✔
578

579
        x = now(CLOCK_REALTIME) - (2*USEC_PER_YEAR + 2*USEC_PER_MONTH);
1✔
580
        assert_se(format_timestamp_relative(buf, sizeof(buf), x));
1✔
581
        log_debug("%s", buf);
1✔
582
        ASSERT_STREQ(buf, "2 years 2 months ago");
1✔
583

584
        /* Months and days */
585
        x = now(CLOCK_REALTIME) - (1*USEC_PER_MONTH + 1*USEC_PER_DAY);
1✔
586
        assert_se(format_timestamp_relative(buf, sizeof(buf), x));
1✔
587
        log_debug("%s", buf);
1✔
588
        ASSERT_STREQ(buf, "1 month 1 day ago");
1✔
589

590
        x = now(CLOCK_REALTIME) - (1*USEC_PER_MONTH + 2*USEC_PER_DAY);
1✔
591
        assert_se(format_timestamp_relative(buf, sizeof(buf), x));
1✔
592
        log_debug("%s", buf);
1✔
593
        ASSERT_STREQ(buf, "1 month 2 days ago");
1✔
594

595
        x = now(CLOCK_REALTIME) - (2*USEC_PER_MONTH + 1*USEC_PER_DAY);
1✔
596
        assert_se(format_timestamp_relative(buf, sizeof(buf), x));
1✔
597
        log_debug("%s", buf);
1✔
598
        ASSERT_STREQ(buf, "2 months 1 day ago");
1✔
599

600
        x = now(CLOCK_REALTIME) - (2*USEC_PER_MONTH + 2*USEC_PER_DAY);
1✔
601
        assert_se(format_timestamp_relative(buf, sizeof(buf), x));
1✔
602
        log_debug("%s", buf);
1✔
603
        ASSERT_STREQ(buf, "2 months 2 days ago");
1✔
604

605
        /* Weeks and days */
606
        x = now(CLOCK_REALTIME) - (1*USEC_PER_WEEK + 1*USEC_PER_DAY);
1✔
607
        assert_se(format_timestamp_relative(buf, sizeof(buf), x));
1✔
608
        log_debug("%s", buf);
1✔
609
        ASSERT_STREQ(buf, "1 week 1 day ago");
1✔
610

611
        x = now(CLOCK_REALTIME) - (1*USEC_PER_WEEK + 2*USEC_PER_DAY);
1✔
612
        assert_se(format_timestamp_relative(buf, sizeof(buf), x));
1✔
613
        log_debug("%s", buf);
1✔
614
        ASSERT_STREQ(buf, "1 week 2 days ago");
1✔
615

616
        x = now(CLOCK_REALTIME) - (2*USEC_PER_WEEK + 1*USEC_PER_DAY);
1✔
617
        assert_se(format_timestamp_relative(buf, sizeof(buf), x));
1✔
618
        log_debug("%s", buf);
1✔
619
        ASSERT_STREQ(buf, "2 weeks 1 day ago");
1✔
620

621
        x = now(CLOCK_REALTIME) - (2*USEC_PER_WEEK + 2*USEC_PER_DAY);
1✔
622
        assert_se(format_timestamp_relative(buf, sizeof(buf), x));
1✔
623
        log_debug("%s", buf);
1✔
624
        ASSERT_STREQ(buf, "2 weeks 2 days ago");
1✔
625
}
1✔
626

627
static void test_format_timestamp_one(usec_t val, TimestampStyle style, const char *result) {
15✔
628
        char buf[FORMAT_TIMESTAMP_MAX];
15✔
629
        const char *t;
15✔
630

631
        t = format_timestamp_style(buf, sizeof(buf), val, style);
15✔
632
        ASSERT_STREQ(t, result);
15✔
633
}
15✔
634

635
TEST(format_timestamp_range) {
1✔
636
        test_format_timestamp_one(0, TIMESTAMP_UTC, NULL);
1✔
637
        test_format_timestamp_one(0, TIMESTAMP_DATE, NULL);
1✔
638
        test_format_timestamp_one(0, TIMESTAMP_US_UTC, NULL);
1✔
639

640
        test_format_timestamp_one(1, TIMESTAMP_UTC, "Thu 1970-01-01 00:00:00 UTC");
1✔
641
        test_format_timestamp_one(1, TIMESTAMP_DATE, "Thu 1970-01-01");
1✔
642
        test_format_timestamp_one(1, TIMESTAMP_US_UTC, "Thu 1970-01-01 00:00:00.000001 UTC");
1✔
643

644
        test_format_timestamp_one(USEC_PER_SEC, TIMESTAMP_UTC, "Thu 1970-01-01 00:00:01 UTC");
1✔
645
        test_format_timestamp_one(USEC_PER_SEC, TIMESTAMP_DATE, "Thu 1970-01-01");
1✔
646
        test_format_timestamp_one(USEC_PER_SEC, TIMESTAMP_US_UTC, "Thu 1970-01-01 00:00:01.000000 UTC");
1✔
647

648
#if SIZEOF_TIME_T == 8
649
        test_format_timestamp_one(USEC_TIMESTAMP_FORMATTABLE_MAX, TIMESTAMP_UTC, "Thu 9999-12-30 23:59:59 UTC");
1✔
650
        test_format_timestamp_one(USEC_TIMESTAMP_FORMATTABLE_MAX, TIMESTAMP_DATE, "Thu 9999-12-30");
1✔
651
        test_format_timestamp_one(USEC_TIMESTAMP_FORMATTABLE_MAX + 1, TIMESTAMP_UTC, "--- XXXX-XX-XX XX:XX:XX UTC");
1✔
652
        test_format_timestamp_one(USEC_TIMESTAMP_FORMATTABLE_MAX + 1, TIMESTAMP_US_UTC, "--- XXXX-XX-XX XX:XX:XX.XXXXXX UTC");
1✔
653
        test_format_timestamp_one(USEC_TIMESTAMP_FORMATTABLE_MAX + 1, TIMESTAMP_DATE, "--- XXXX-XX-XX");
1✔
654
#elif SIZEOF_TIME_T == 4
655
        test_format_timestamp_one(USEC_TIMESTAMP_FORMATTABLE_MAX, TIMESTAMP_UTC, "Mon 2038-01-18 03:14:07 UTC");
656
        test_format_timestamp_one(USEC_TIMESTAMP_FORMATTABLE_MAX, TIMESTAMP_DATE, "Mon 2038-01-18");
657
        test_format_timestamp_one(USEC_TIMESTAMP_FORMATTABLE_MAX + 1, TIMESTAMP_UTC, "--- XXXX-XX-XX XX:XX:XX UTC");
658
        test_format_timestamp_one(USEC_TIMESTAMP_FORMATTABLE_MAX + 1, TIMESTAMP_US_UTC, "--- XXXX-XX-XX XX:XX:XX.XXXXXX UTC");
659
        test_format_timestamp_one(USEC_TIMESTAMP_FORMATTABLE_MAX + 1, TIMESTAMP_DATE, "--- XXXX-XX-XX");
660
#endif
661

662
        test_format_timestamp_one(USEC_INFINITY, TIMESTAMP_UTC, NULL);
1✔
663
}
1✔
664

665
static void test_parse_timestamp_one(const char *str, usec_t max_diff, usec_t expected) {
316✔
666
        usec_t usec = USEC_INFINITY;
316✔
667
        int r;
316✔
668

669
        r = parse_timestamp(str, &usec);
316✔
670
        log_debug("/* %s(%s): max_diff="USEC_FMT", expected="USEC_FMT", result="USEC_FMT" */", __func__, str, max_diff, expected, usec);
316✔
671
        assert_se(r >= 0);
316✔
672
        assert_se(usec >= expected);
316✔
673
        assert_se(usec_sub_unsigned(usec, expected) <= max_diff);
632✔
674
}
316✔
675

676
static bool time_is_zero(usec_t usec) {
6✔
677
        const char *s;
6✔
678

679
        s = FORMAT_TIMESTAMP(usec);
6✔
680
        return strstr(s, " 00:00:00 ");
6✔
681
}
682

683
static bool timezone_equal(usec_t today, usec_t target) {
4✔
684
        const char *s, *t, *sz, *tz;
4✔
685

686
        s = FORMAT_TIMESTAMP(today);
4✔
687
        t = FORMAT_TIMESTAMP(target);
4✔
688
        assert_se(sz = strrchr(s, ' '));
4✔
689
        assert_se(tz = strrchr(t, ' '));
4✔
690
        log_debug("%s("USEC_FMT", "USEC_FMT") -> %s, %s", __func__, today, target, s, t);
4✔
691
        return streq(sz, tz);
4✔
692
}
693

694
static void test_parse_timestamp_impl(const char *tz) {
2✔
695
        usec_t today, today2, now_usec;
2✔
696

697
        /* Invalid: Ensure that systemctl reboot --when=show and --when=cancel
698
         * will not result in ambiguities */
699
        assert_se(parse_timestamp("show", NULL) == -EINVAL);
2✔
700
        assert_se(parse_timestamp("cancel", NULL) == -EINVAL);
2✔
701

702
        /* UTC */
703
        test_parse_timestamp_one("Thu 1970-01-01 00:01 UTC", 0, USEC_PER_MINUTE);
2✔
704
        test_parse_timestamp_one("Thu 1970-01-01 00:00:01 UTC", 0, USEC_PER_SEC);
2✔
705
        test_parse_timestamp_one("Thu 1970-01-01 00:00:01.001 UTC", 0, USEC_PER_SEC + 1000);
2✔
706
        test_parse_timestamp_one("Thu 1970-01-01 00:00:01.0010 UTC", 0, USEC_PER_SEC + 1000);
2✔
707

708
        test_parse_timestamp_one("Thu 70-01-01 00:01 UTC", 0, USEC_PER_MINUTE);
2✔
709
        test_parse_timestamp_one("Thu 70-01-01 00:00:01 UTC", 0, USEC_PER_SEC);
2✔
710
        test_parse_timestamp_one("Thu 70-01-01 00:00:01.001 UTC", 0, USEC_PER_SEC + 1000);
2✔
711
        test_parse_timestamp_one("Thu 70-01-01 00:00:01.0010 UTC", 0, USEC_PER_SEC + 1000);
2✔
712

713
        test_parse_timestamp_one("1970-01-01 00:01 UTC", 0, USEC_PER_MINUTE);
2✔
714
        test_parse_timestamp_one("1970-01-01 00:00:01 UTC", 0, USEC_PER_SEC);
2✔
715
        test_parse_timestamp_one("1970-01-01 00:00:01.001 UTC", 0, USEC_PER_SEC + 1000);
2✔
716
        test_parse_timestamp_one("1970-01-01 00:00:01.0010 UTC", 0, USEC_PER_SEC + 1000);
2✔
717

718
        test_parse_timestamp_one("70-01-01 00:01 UTC", 0, USEC_PER_MINUTE);
2✔
719
        test_parse_timestamp_one("70-01-01 00:00:01 UTC", 0, USEC_PER_SEC);
2✔
720
        test_parse_timestamp_one("70-01-01 00:00:01.001 UTC", 0, USEC_PER_SEC + 1000);
2✔
721
        test_parse_timestamp_one("70-01-01 00:00:01.0010 UTC", 0, USEC_PER_SEC + 1000);
2✔
722

723
        /* Examples from RFC3339 */
724
        test_parse_timestamp_one("1985-04-12T23:20:50.52Z", 0, 482196050 * USEC_PER_SEC + 520000);
2✔
725
        test_parse_timestamp_one("1996-12-19T16:39:57-08:00", 0, 851042397 * USEC_PER_SEC + 000000);
2✔
726
        test_parse_timestamp_one("1996-12-20T00:39:57Z", 0, 851042397 * USEC_PER_SEC + 000000);
2✔
727
        test_parse_timestamp_one("1990-12-31T23:59:60Z", 0, 662688000 * USEC_PER_SEC + 000000);
2✔
728
        test_parse_timestamp_one("1990-12-31T15:59:60-08:00", 0, 662688000 * USEC_PER_SEC + 000000);
2✔
729
        assert_se(parse_timestamp("1937-01-01T12:00:27.87+00:20", NULL) == -ERANGE); /* we don't support pre-epoch timestamps */
2✔
730
        /* We accept timestamps without seconds as well */
731
        test_parse_timestamp_one("1996-12-20T00:39Z", 0, (851042397 - 57) * USEC_PER_SEC + 000000);
2✔
732
        test_parse_timestamp_one("1990-12-31T15:59-08:00", 0, (662688000-60) * USEC_PER_SEC + 000000);
2✔
733
        /* We drop day-of-week before parsing the timestamp */
734
        test_parse_timestamp_one("Thu 1970-01-01T00:01 UTC", 0, USEC_PER_MINUTE);
2✔
735
        test_parse_timestamp_one("Thu 1970-01-01T00:00:01 UTC", 0, USEC_PER_SEC);
2✔
736
        test_parse_timestamp_one("Thu 1970-01-01T00:01Z", 0, USEC_PER_MINUTE);
2✔
737
        test_parse_timestamp_one("Thu 1970-01-01T00:00:01Z", 0, USEC_PER_SEC);
2✔
738
        /* RFC3339-style timezones can be welded to all formats */
739
        assert_se(parse_timestamp("today UTC", &today) == 0);
2✔
740
        assert_se(parse_timestamp("todayZ", &today2) == 0);
2✔
741
        assert_se(today == today2);
2✔
742
        assert_se(parse_timestamp("today +0200", &today) == 0);
2✔
743
        assert_se(parse_timestamp("today+02:00", &today2) == 0);
2✔
744
        assert_se(today == today2);
2✔
745

746
        /* https://ijmacd.github.io/rfc3339-iso8601/ */
747
        test_parse_timestamp_one("2023-09-06 12:49:27-00:00", 0, 1694004567 * USEC_PER_SEC + 000000);
2✔
748
        test_parse_timestamp_one("2023-09-06 12:49:27.284-00:00", 0, 1694004567 * USEC_PER_SEC + 284000);
2✔
749
        test_parse_timestamp_one("2023-09-06 12:49:27.284029Z", 0, 1694004567 * USEC_PER_SEC + 284029);
2✔
750
        test_parse_timestamp_one("2023-09-06 12:49:27.284Z", 0, 1694004567 * USEC_PER_SEC + 284000);
2✔
751
        test_parse_timestamp_one("2023-09-06 12:49:27.28Z", 0, 1694004567 * USEC_PER_SEC + 280000);
2✔
752
        test_parse_timestamp_one("2023-09-06 12:49:27.2Z", 0, 1694004567 * USEC_PER_SEC + 200000);
2✔
753
        test_parse_timestamp_one("2023-09-06 12:49:27Z", 0, 1694004567 * USEC_PER_SEC + 000000);
2✔
754
        test_parse_timestamp_one("2023-09-06 14:49:27+02:00", 0, 1694004567 * USEC_PER_SEC + 000000);
2✔
755
        test_parse_timestamp_one("2023-09-06 14:49:27.2+02:00", 0, 1694004567 * USEC_PER_SEC + 200000);
2✔
756
        test_parse_timestamp_one("2023-09-06 14:49:27.28+02:00", 0, 1694004567 * USEC_PER_SEC + 280000);
2✔
757
        test_parse_timestamp_one("2023-09-06 14:49:27.284+02:00", 0, 1694004567 * USEC_PER_SEC + 284000);
2✔
758
        test_parse_timestamp_one("2023-09-06 14:49:27.284029+02:00", 0, 1694004567 * USEC_PER_SEC + 284029);
2✔
759
        test_parse_timestamp_one("2023-09-06T12:49:27+00:00", 0, 1694004567 * USEC_PER_SEC + 000000);
2✔
760
        test_parse_timestamp_one("2023-09-06T12:49:27-00:00", 0, 1694004567 * USEC_PER_SEC + 000000);
2✔
761
        test_parse_timestamp_one("2023-09-06T12:49:27.284+00:00", 0, 1694004567 * USEC_PER_SEC + 284000);
2✔
762
        test_parse_timestamp_one("2023-09-06T12:49:27.284-00:00", 0, 1694004567 * USEC_PER_SEC + 284000);
2✔
763
        test_parse_timestamp_one("2023-09-06T12:49:27.284029Z", 0, 1694004567 * USEC_PER_SEC + 284029);
2✔
764
        test_parse_timestamp_one("2023-09-06T12:49:27.284Z", 0, 1694004567 * USEC_PER_SEC + 284000);
2✔
765
        test_parse_timestamp_one("2023-09-06T12:49:27.28Z", 0, 1694004567 * USEC_PER_SEC + 280000);
2✔
766
        test_parse_timestamp_one("2023-09-06T12:49:27.2Z", 0, 1694004567 * USEC_PER_SEC + 200000);
2✔
767
        test_parse_timestamp_one("2023-09-06T12:49:27Z", 0, 1694004567 * USEC_PER_SEC + 000000);
2✔
768
        test_parse_timestamp_one("2023-09-06T14:49:27+02:00", 0, 1694004567 * USEC_PER_SEC + 000000);
2✔
769
        test_parse_timestamp_one("2023-09-06T14:49:27.284+02:00", 0, 1694004567 * USEC_PER_SEC + 284000);
2✔
770
        test_parse_timestamp_one("2023-09-06T14:49:27.284029+02:00", 0, 1694004567 * USEC_PER_SEC + 284029);
2✔
771
        test_parse_timestamp_one("2023-09-06T21:34:27+08:45", 0, 1694004567 * USEC_PER_SEC + 000000);
2✔
772

773
        if (timezone_is_valid("Asia/Tokyo", LOG_DEBUG)) {
2✔
774
                /* Asia/Tokyo (+0900) */
775
                test_parse_timestamp_one("Thu 1970-01-01 09:01 Asia/Tokyo", 0, USEC_PER_MINUTE);
2✔
776
                test_parse_timestamp_one("Thu 1970-01-01 09:00:01 Asia/Tokyo", 0, USEC_PER_SEC);
2✔
777
                test_parse_timestamp_one("Thu 1970-01-01 09:00:01.001 Asia/Tokyo", 0, USEC_PER_SEC + 1000);
2✔
778
                test_parse_timestamp_one("Thu 1970-01-01 09:00:01.0010 Asia/Tokyo", 0, USEC_PER_SEC + 1000);
2✔
779

780
                test_parse_timestamp_one("Thu 70-01-01 09:01 Asia/Tokyo", 0, USEC_PER_MINUTE);
2✔
781
                test_parse_timestamp_one("Thu 70-01-01 09:00:01 Asia/Tokyo", 0, USEC_PER_SEC);
2✔
782
                test_parse_timestamp_one("Thu 70-01-01 09:00:01.001 Asia/Tokyo", 0, USEC_PER_SEC + 1000);
2✔
783
                test_parse_timestamp_one("Thu 70-01-01 09:00:01.0010 Asia/Tokyo", 0, USEC_PER_SEC + 1000);
2✔
784

785
                test_parse_timestamp_one("1970-01-01 09:01 Asia/Tokyo", 0, USEC_PER_MINUTE);
2✔
786
                test_parse_timestamp_one("1970-01-01 09:00:01 Asia/Tokyo", 0, USEC_PER_SEC);
2✔
787
                test_parse_timestamp_one("1970-01-01 09:00:01.001 Asia/Tokyo", 0, USEC_PER_SEC + 1000);
2✔
788
                test_parse_timestamp_one("1970-01-01 09:00:01.0010 Asia/Tokyo", 0, USEC_PER_SEC + 1000);
2✔
789

790
                test_parse_timestamp_one("70-01-01 09:01 Asia/Tokyo", 0, USEC_PER_MINUTE);
2✔
791
                test_parse_timestamp_one("70-01-01 09:00:01 Asia/Tokyo", 0, USEC_PER_SEC);
2✔
792
                test_parse_timestamp_one("70-01-01 09:00:01.001 Asia/Tokyo", 0, USEC_PER_SEC + 1000);
2✔
793
                test_parse_timestamp_one("70-01-01 09:00:01.0010 Asia/Tokyo", 0, USEC_PER_SEC + 1000);
2✔
794
        }
795

796
        if (streq_ptr(tz, "Asia/Tokyo")) {
2✔
797
                /* JST (+0900) */
798
                test_parse_timestamp_one("Thu 1970-01-01 09:01 JST", 0, USEC_PER_MINUTE);
×
799
                test_parse_timestamp_one("Thu 1970-01-01 09:00:01 JST", 0, USEC_PER_SEC);
×
800
                test_parse_timestamp_one("Thu 1970-01-01 09:00:01.001 JST", 0, USEC_PER_SEC + 1000);
×
801
                test_parse_timestamp_one("Thu 1970-01-01 09:00:01.0010 JST", 0, USEC_PER_SEC + 1000);
×
802

803
                test_parse_timestamp_one("Thu 70-01-01 09:01 JST", 0, USEC_PER_MINUTE);
×
804
                test_parse_timestamp_one("Thu 70-01-01 09:00:01 JST", 0, USEC_PER_SEC);
×
805
                test_parse_timestamp_one("Thu 70-01-01 09:00:01.001 JST", 0, USEC_PER_SEC + 1000);
×
806
                test_parse_timestamp_one("Thu 70-01-01 09:00:01.0010 JST", 0, USEC_PER_SEC + 1000);
×
807

808
                test_parse_timestamp_one("1970-01-01 09:01 JST", 0, USEC_PER_MINUTE);
×
809
                test_parse_timestamp_one("1970-01-01 09:00:01 JST", 0, USEC_PER_SEC);
×
810
                test_parse_timestamp_one("1970-01-01 09:00:01.001 JST", 0, USEC_PER_SEC + 1000);
×
811
                test_parse_timestamp_one("1970-01-01 09:00:01.0010 JST", 0, USEC_PER_SEC + 1000);
×
812

813
                test_parse_timestamp_one("70-01-01 09:01 JST", 0, USEC_PER_MINUTE);
×
814
                test_parse_timestamp_one("70-01-01 09:00:01 JST", 0, USEC_PER_SEC);
×
815
                test_parse_timestamp_one("70-01-01 09:00:01.001 JST", 0, USEC_PER_SEC + 1000);
×
816
                test_parse_timestamp_one("70-01-01 09:00:01.0010 JST", 0, USEC_PER_SEC + 1000);
×
817
        }
818

819
        if (timezone_is_valid("America/New_York", LOG_DEBUG)) {
2✔
820
                /* America/New_York (-0500) */
821
                test_parse_timestamp_one("Wed 1969-12-31 19:01 America/New_York", 0, USEC_PER_MINUTE);
2✔
822
                test_parse_timestamp_one("Wed 1969-12-31 19:00:01 America/New_York", 0, USEC_PER_SEC);
2✔
823
                test_parse_timestamp_one("Wed 1969-12-31 19:00:01.001 America/New_York", 0, USEC_PER_SEC + 1000);
2✔
824
                test_parse_timestamp_one("Wed 1969-12-31 19:00:01.0010 America/New_York", 0, USEC_PER_SEC + 1000);
2✔
825

826
                test_parse_timestamp_one("Wed 69-12-31 19:01 America/New_York", 0, USEC_PER_MINUTE);
2✔
827
                test_parse_timestamp_one("Wed 69-12-31 19:00:01 America/New_York", 0, USEC_PER_SEC);
2✔
828
                test_parse_timestamp_one("Wed 69-12-31 19:00:01.001 America/New_York", 0, USEC_PER_SEC + 1000);
2✔
829
                test_parse_timestamp_one("Wed 69-12-31 19:00:01.0010 America/New_York", 0, USEC_PER_SEC + 1000);
2✔
830

831
                test_parse_timestamp_one("1969-12-31 19:01 America/New_York", 0, USEC_PER_MINUTE);
2✔
832
                test_parse_timestamp_one("1969-12-31 19:00:01 America/New_York", 0, USEC_PER_SEC);
2✔
833
                test_parse_timestamp_one("1969-12-31 19:00:01.001 America/New_York", 0, USEC_PER_SEC + 1000);
2✔
834
                test_parse_timestamp_one("1969-12-31 19:00:01.0010 America/New_York", 0, USEC_PER_SEC + 1000);
2✔
835

836
                test_parse_timestamp_one("69-12-31 19:01 America/New_York", 0, USEC_PER_MINUTE);
2✔
837
                test_parse_timestamp_one("69-12-31 19:00:01 America/New_York", 0, USEC_PER_SEC);
2✔
838
                test_parse_timestamp_one("69-12-31 19:00:01.001 America/New_York", 0, USEC_PER_SEC + 1000);
2✔
839
                test_parse_timestamp_one("69-12-31 19:00:01.0010 America/New_York", 0, USEC_PER_SEC + 1000);
2✔
840
        }
841

842
        if (streq_ptr(tz, "America/New_York")) {
2✔
843
                /* EST (-0500) */
844
                test_parse_timestamp_one("Wed 1969-12-31 19:01 EST", 0, USEC_PER_MINUTE);
×
845
                test_parse_timestamp_one("Wed 1969-12-31 19:00:01 EST", 0, USEC_PER_SEC);
×
846
                test_parse_timestamp_one("Wed 1969-12-31 19:00:01.001 EST", 0, USEC_PER_SEC + 1000);
×
847
                test_parse_timestamp_one("Wed 1969-12-31 19:00:01.0010 EST", 0, USEC_PER_SEC + 1000);
×
848

849
                test_parse_timestamp_one("Wed 69-12-31 19:01 EST", 0, USEC_PER_MINUTE);
×
850
                test_parse_timestamp_one("Wed 69-12-31 19:00:01 EST", 0, USEC_PER_SEC);
×
851
                test_parse_timestamp_one("Wed 69-12-31 19:00:01.001 EST", 0, USEC_PER_SEC + 1000);
×
852
                test_parse_timestamp_one("Wed 69-12-31 19:00:01.0010 EST", 0, USEC_PER_SEC + 1000);
×
853

854
                test_parse_timestamp_one("1969-12-31 19:01 EST", 0, USEC_PER_MINUTE);
×
855
                test_parse_timestamp_one("1969-12-31 19:00:01 EST", 0, USEC_PER_SEC);
×
856
                test_parse_timestamp_one("1969-12-31 19:00:01.001 EST", 0, USEC_PER_SEC + 1000);
×
857
                test_parse_timestamp_one("1969-12-31 19:00:01.0010 EST", 0, USEC_PER_SEC + 1000);
×
858

859
                test_parse_timestamp_one("69-12-31 19:01 EST", 0, USEC_PER_MINUTE);
×
860
                test_parse_timestamp_one("69-12-31 19:00:01 EST", 0, USEC_PER_SEC);
×
861
                test_parse_timestamp_one("69-12-31 19:00:01.001 EST", 0, USEC_PER_SEC + 1000);
×
862
                test_parse_timestamp_one("69-12-31 19:00:01.0010 EST", 0, USEC_PER_SEC + 1000);
×
863
        }
864

865
        if (timezone_is_valid("NZ", LOG_DEBUG)) {
2✔
866
                /* NZ (+1200) */
867
                test_parse_timestamp_one("Thu 1970-01-01 12:01 NZ", 0, USEC_PER_MINUTE);
2✔
868
                test_parse_timestamp_one("Thu 1970-01-01 12:00:01 NZ", 0, USEC_PER_SEC);
2✔
869
                test_parse_timestamp_one("Thu 1970-01-01 12:00:01.001 NZ", 0, USEC_PER_SEC + 1000);
2✔
870
                test_parse_timestamp_one("Thu 1970-01-01 12:00:01.0010 NZ", 0, USEC_PER_SEC + 1000);
2✔
871

872
                test_parse_timestamp_one("Thu 70-01-01 12:01 NZ", 0, USEC_PER_MINUTE);
2✔
873
                test_parse_timestamp_one("Thu 70-01-01 12:00:01 NZ", 0, USEC_PER_SEC);
2✔
874
                test_parse_timestamp_one("Thu 70-01-01 12:00:01.001 NZ", 0, USEC_PER_SEC + 1000);
2✔
875
                test_parse_timestamp_one("Thu 70-01-01 12:00:01.0010 NZ", 0, USEC_PER_SEC + 1000);
2✔
876

877
                test_parse_timestamp_one("1970-01-01 12:01 NZ", 0, USEC_PER_MINUTE);
2✔
878
                test_parse_timestamp_one("1970-01-01 12:00:01 NZ", 0, USEC_PER_SEC);
2✔
879
                test_parse_timestamp_one("1970-01-01 12:00:01.001 NZ", 0, USEC_PER_SEC + 1000);
2✔
880
                test_parse_timestamp_one("1970-01-01 12:00:01.0010 NZ", 0, USEC_PER_SEC + 1000);
2✔
881

882
                test_parse_timestamp_one("70-01-01 12:01 NZ", 0, USEC_PER_MINUTE);
2✔
883
                test_parse_timestamp_one("70-01-01 12:00:01 NZ", 0, USEC_PER_SEC);
2✔
884
                test_parse_timestamp_one("70-01-01 12:00:01.001 NZ", 0, USEC_PER_SEC + 1000);
2✔
885
                test_parse_timestamp_one("70-01-01 12:00:01.0010 NZ", 0, USEC_PER_SEC + 1000);
2✔
886
        }
887

888
        /* -06 */
889
        test_parse_timestamp_one("Wed 1969-12-31 18:01 -06", 0, USEC_PER_MINUTE);
2✔
890
        test_parse_timestamp_one("Wed 1969-12-31 18:00:01 -06", 0, USEC_PER_SEC);
2✔
891
        test_parse_timestamp_one("Wed 1969-12-31 18:00:01.001 -06", 0, USEC_PER_SEC + 1000);
2✔
892
        test_parse_timestamp_one("Wed 1969-12-31 18:00:01.0010 -06", 0, USEC_PER_SEC + 1000);
2✔
893

894
        test_parse_timestamp_one("Wed 69-12-31 18:01 -06", 0, USEC_PER_MINUTE);
2✔
895
        test_parse_timestamp_one("Wed 69-12-31 18:00:01 -06", 0, USEC_PER_SEC);
2✔
896
        test_parse_timestamp_one("Wed 69-12-31 18:00:01.001 -06", 0, USEC_PER_SEC + 1000);
2✔
897
        test_parse_timestamp_one("Wed 69-12-31 18:00:01.0010 -06", 0, USEC_PER_SEC + 1000);
2✔
898

899
        test_parse_timestamp_one("1969-12-31 18:01 -06", 0, USEC_PER_MINUTE);
2✔
900
        test_parse_timestamp_one("1969-12-31 18:00:01 -06", 0, USEC_PER_SEC);
2✔
901
        test_parse_timestamp_one("1969-12-31 18:00:01.001 -06", 0, USEC_PER_SEC + 1000);
2✔
902
        test_parse_timestamp_one("1969-12-31 18:00:01.0010 -06", 0, USEC_PER_SEC + 1000);
2✔
903

904
        test_parse_timestamp_one("69-12-31 18:01 -06", 0, USEC_PER_MINUTE);
2✔
905
        test_parse_timestamp_one("69-12-31 18:00:01 -06", 0, USEC_PER_SEC);
2✔
906
        test_parse_timestamp_one("69-12-31 18:00:01.001 -06", 0, USEC_PER_SEC + 1000);
2✔
907
        test_parse_timestamp_one("69-12-31 18:00:01.0010 -06", 0, USEC_PER_SEC + 1000);
2✔
908

909
        /* -0600 */
910
        test_parse_timestamp_one("Wed 1969-12-31 18:01 -0600", 0, USEC_PER_MINUTE);
2✔
911
        test_parse_timestamp_one("Wed 1969-12-31 18:00:01 -0600", 0, USEC_PER_SEC);
2✔
912
        test_parse_timestamp_one("Wed 1969-12-31 18:00:01.001 -0600", 0, USEC_PER_SEC + 1000);
2✔
913
        test_parse_timestamp_one("Wed 1969-12-31 18:00:01.0010 -0600", 0, USEC_PER_SEC + 1000);
2✔
914

915
        test_parse_timestamp_one("Wed 69-12-31 18:01 -0600", 0, USEC_PER_MINUTE);
2✔
916
        test_parse_timestamp_one("Wed 69-12-31 18:00:01 -0600", 0, USEC_PER_SEC);
2✔
917
        test_parse_timestamp_one("Wed 69-12-31 18:00:01.001 -0600", 0, USEC_PER_SEC + 1000);
2✔
918
        test_parse_timestamp_one("Wed 69-12-31 18:00:01.0010 -0600", 0, USEC_PER_SEC + 1000);
2✔
919

920
        test_parse_timestamp_one("1969-12-31 18:01 -0600", 0, USEC_PER_MINUTE);
2✔
921
        test_parse_timestamp_one("1969-12-31 18:00:01 -0600", 0, USEC_PER_SEC);
2✔
922
        test_parse_timestamp_one("1969-12-31 18:00:01.001 -0600", 0, USEC_PER_SEC + 1000);
2✔
923
        test_parse_timestamp_one("1969-12-31 18:00:01.0010 -0600", 0, USEC_PER_SEC + 1000);
2✔
924

925
        test_parse_timestamp_one("69-12-31 18:01 -0600", 0, USEC_PER_MINUTE);
2✔
926
        test_parse_timestamp_one("69-12-31 18:00:01 -0600", 0, USEC_PER_SEC);
2✔
927
        test_parse_timestamp_one("69-12-31 18:00:01.001 -0600", 0, USEC_PER_SEC + 1000);
2✔
928
        test_parse_timestamp_one("69-12-31 18:00:01.0010 -0600", 0, USEC_PER_SEC + 1000);
2✔
929

930
        /* -06:00 */
931
        test_parse_timestamp_one("Wed 1969-12-31 18:01 -06:00", 0, USEC_PER_MINUTE);
2✔
932
        test_parse_timestamp_one("Wed 1969-12-31 18:00:01 -06:00", 0, USEC_PER_SEC);
2✔
933
        test_parse_timestamp_one("Wed 1969-12-31 18:00:01.001 -06:00", 0, USEC_PER_SEC + 1000);
2✔
934
        test_parse_timestamp_one("Wed 1969-12-31 18:00:01.0010 -06:00", 0, USEC_PER_SEC + 1000);
2✔
935

936
        test_parse_timestamp_one("Wed 69-12-31 18:01 -06:00", 0, USEC_PER_MINUTE);
2✔
937
        test_parse_timestamp_one("Wed 69-12-31 18:00:01 -06:00", 0, USEC_PER_SEC);
2✔
938
        test_parse_timestamp_one("Wed 69-12-31 18:00:01.001 -06:00", 0, USEC_PER_SEC + 1000);
2✔
939
        test_parse_timestamp_one("Wed 69-12-31 18:00:01.0010 -06:00", 0, USEC_PER_SEC + 1000);
2✔
940

941
        test_parse_timestamp_one("1969-12-31 18:01 -06:00", 0, USEC_PER_MINUTE);
2✔
942
        test_parse_timestamp_one("1969-12-31 18:00:01 -06:00", 0, USEC_PER_SEC);
2✔
943
        test_parse_timestamp_one("1969-12-31 18:00:01.001 -06:00", 0, USEC_PER_SEC + 1000);
2✔
944
        test_parse_timestamp_one("1969-12-31 18:00:01.0010 -06:00", 0, USEC_PER_SEC + 1000);
2✔
945

946
        test_parse_timestamp_one("69-12-31 18:01 -06:00", 0, USEC_PER_MINUTE);
2✔
947
        test_parse_timestamp_one("69-12-31 18:00:01 -06:00", 0, USEC_PER_SEC);
2✔
948
        test_parse_timestamp_one("69-12-31 18:00:01.001 -06:00", 0, USEC_PER_SEC + 1000);
2✔
949
        test_parse_timestamp_one("69-12-31 18:00:01.0010 -06:00", 0, USEC_PER_SEC + 1000);
2✔
950

951
        /* without date */
952
        assert_se(parse_timestamp("today", &today) == 0);
2✔
953
        if (time_is_zero(today)) {
2✔
954
                test_parse_timestamp_one("00:01", 0, today + USEC_PER_MINUTE);
2✔
955
                test_parse_timestamp_one("00:00:01", 0, today + USEC_PER_SEC);
2✔
956
                test_parse_timestamp_one("00:00:01.001", 0, today + USEC_PER_SEC + 1000);
2✔
957
                test_parse_timestamp_one("00:00:01.0010", 0, today + USEC_PER_SEC + 1000);
2✔
958

959
                if (timezone_equal(today, today + USEC_PER_DAY) && time_is_zero(today + USEC_PER_DAY))
2✔
960
                        test_parse_timestamp_one("tomorrow", 0, today + USEC_PER_DAY);
2✔
961
                if (timezone_equal(today, today - USEC_PER_DAY) && time_is_zero(today - USEC_PER_DAY))
2✔
962
                        test_parse_timestamp_one("yesterday", 0, today - USEC_PER_DAY);
2✔
963
        }
964

965
        /* with timezone */
966
        if (tz) {
2✔
967
                _cleanup_free_ char *s = NULL;
1✔
968

969
                ASSERT_NOT_NULL(s = strjoin("Fri 2012-11-23 23:02:15 ", tz));
1✔
970
                ASSERT_OK(parse_timestamp(s, NULL));
1✔
971
        }
972

973
        /* relative */
974
        assert_se(parse_timestamp("now", &now_usec) == 0);
2✔
975
        test_parse_timestamp_one("+5hours", USEC_PER_MINUTE, now_usec + 5 * USEC_PER_HOUR);
2✔
976
        if (now_usec >= 10 * USEC_PER_DAY)
2✔
977
                test_parse_timestamp_one("-10days", USEC_PER_MINUTE, now_usec - 10 * USEC_PER_DAY);
2✔
978
        test_parse_timestamp_one("2weeks left", USEC_PER_MINUTE, now_usec + 2 * USEC_PER_WEEK);
2✔
979
        if (now_usec >= 30 * USEC_PER_MINUTE)
2✔
980
                test_parse_timestamp_one("30minutes ago", USEC_PER_MINUTE, now_usec - 30 * USEC_PER_MINUTE);
2✔
981
}
2✔
982

983
TEST(parse_timestamp) {
1✔
984
        test_parse_timestamp_impl(NULL);
1✔
985
}
1✔
986

987
static void test_parse_timestamp_with_tz_one(const char *tz) {
1✔
988
        const char *saved_tz, *colon_tz;
1✔
989

990
        if (!timezone_is_valid(tz, LOG_DEBUG))
1✔
991
                return;
992

993
        log_info("/* %s(%s) */", __func__, tz);
1✔
994

995
        saved_tz = getenv("TZ");
1✔
996

997
        assert_se(colon_tz = strjoina(":", tz));
5✔
998
        assert_se(setenv("TZ", colon_tz, 1) >= 0);
1✔
999
        tzset();
1✔
1000
        log_debug("%s: tzname[0]=%s, tzname[1]=%s", tz, strempty(tzname[0]), strempty(tzname[1]));
1✔
1001

1002
        test_parse_timestamp_impl(tz);
1✔
1003

1004
        assert_se(set_unset_env("TZ", saved_tz, true) == 0);
1✔
1005
        tzset();
1✔
1006
}
1007

1008
TEST(parse_timestamp_with_tz) {
1✔
1009
        _cleanup_strv_free_ char **timezones = NULL;
×
1010

1011
        test_parse_timestamp_with_tz_one("UTC");
1✔
1012

1013
        if (!slow_tests_enabled())
1✔
1014
                return (void) log_tests_skipped("slow tests are disabled");
1✔
1015

1016
        assert_se(get_timezones(&timezones) >= 0);
×
1017
        STRV_FOREACH(tz, timezones)
×
1018
                test_parse_timestamp_with_tz_one(*tz);
×
1019
}
1020

1021
TEST(deserialize_dual_timestamp) {
1✔
1022
        int r;
1✔
1023
        dual_timestamp t;
1✔
1024

1025
        r = deserialize_dual_timestamp("1234 5678", &t);
1✔
1026
        assert_se(r == 0);
1✔
1027
        assert_se(t.realtime == 1234);
1✔
1028
        assert_se(t.monotonic == 5678);
1✔
1029

1030
        r = deserialize_dual_timestamp("1234x 5678", &t);
1✔
1031
        assert_se(r == -EINVAL);
1✔
1032

1033
        r = deserialize_dual_timestamp("1234 5678y", &t);
1✔
1034
        assert_se(r == -EINVAL);
1✔
1035

1036
        r = deserialize_dual_timestamp("-1234 5678", &t);
1✔
1037
        assert_se(r == -EINVAL);
1✔
1038

1039
        r = deserialize_dual_timestamp("1234 -5678", &t);
1✔
1040
        assert_se(r == -EINVAL);
1✔
1041

1042
        /* Check that output wasn't modified. */
1043
        assert_se(t.realtime == 1234);
1✔
1044
        assert_se(t.monotonic == 5678);
1✔
1045

1046
        r = deserialize_dual_timestamp("+123 567", &t);
1✔
1047
        assert_se(r == 0);
1✔
1048
        assert_se(t.realtime == 123);
1✔
1049
        assert_se(t.monotonic == 567);
1✔
1050

1051
        /* Check that we get "infinity" on overflow. */
1052
        r = deserialize_dual_timestamp("18446744073709551617 0", &t);
1✔
1053
        assert_se(r == 0);
1✔
1054
        assert_se(t.realtime == USEC_INFINITY);
1✔
1055
        assert_se(t.monotonic == 0);
1✔
1056
}
1✔
1057

1058
static void assert_similar(usec_t a, usec_t b) {
8✔
1059
        usec_t d;
8✔
1060

1061
        if (a > b)
8✔
1062
                d = a - b;
×
1063
        else
1064
                d = b - a;
8✔
1065

1066
        assert_se(d < 10*USEC_PER_SEC);
8✔
1067
}
8✔
1068

1069
TEST(usec_shift_clock) {
1✔
1070
        usec_t rt, mn, bt;
1✔
1071

1072
        rt = now(CLOCK_REALTIME);
1✔
1073
        mn = now(CLOCK_MONOTONIC);
1✔
1074
        bt = now(CLOCK_BOOTTIME);
1✔
1075

1076
        assert_se(usec_shift_clock(USEC_INFINITY, CLOCK_REALTIME, CLOCK_MONOTONIC) == USEC_INFINITY);
1✔
1077

1078
        assert_similar(usec_shift_clock(rt + USEC_PER_HOUR, CLOCK_REALTIME, CLOCK_MONOTONIC), mn + USEC_PER_HOUR);
1✔
1079
        assert_similar(usec_shift_clock(rt + 2*USEC_PER_HOUR, CLOCK_REALTIME, CLOCK_BOOTTIME), bt + 2*USEC_PER_HOUR);
1✔
1080
        assert_se(usec_shift_clock(rt + 3*USEC_PER_HOUR, CLOCK_REALTIME, CLOCK_REALTIME_ALARM) == rt + 3*USEC_PER_HOUR);
1✔
1081

1082
        assert_similar(usec_shift_clock(mn + 4*USEC_PER_HOUR, CLOCK_MONOTONIC, CLOCK_REALTIME_ALARM), rt + 4*USEC_PER_HOUR);
1✔
1083
        assert_similar(usec_shift_clock(mn + 5*USEC_PER_HOUR, CLOCK_MONOTONIC, CLOCK_BOOTTIME), bt + 5*USEC_PER_HOUR);
1✔
1084
        assert_se(usec_shift_clock(mn + 6*USEC_PER_HOUR, CLOCK_MONOTONIC, CLOCK_MONOTONIC) == mn + 6*USEC_PER_HOUR);
1✔
1085

1086
        assert_similar(usec_shift_clock(bt + 7*USEC_PER_HOUR, CLOCK_BOOTTIME, CLOCK_MONOTONIC), mn + 7*USEC_PER_HOUR);
1✔
1087
        assert_similar(usec_shift_clock(bt + 8*USEC_PER_HOUR, CLOCK_BOOTTIME, CLOCK_REALTIME_ALARM), rt + 8*USEC_PER_HOUR);
1✔
1088
        assert_se(usec_shift_clock(bt + 9*USEC_PER_HOUR, CLOCK_BOOTTIME, CLOCK_BOOTTIME) == bt + 9*USEC_PER_HOUR);
1✔
1089

1090
        if (mn > USEC_PER_MINUTE) {
1✔
1091
                assert_similar(usec_shift_clock(rt - 30 * USEC_PER_SEC, CLOCK_REALTIME_ALARM, CLOCK_MONOTONIC), mn - 30 * USEC_PER_SEC);
1✔
1092
                assert_similar(usec_shift_clock(rt - 50 * USEC_PER_SEC, CLOCK_REALTIME, CLOCK_BOOTTIME), bt - 50 * USEC_PER_SEC);
1✔
1093
        }
1094
}
1✔
1095

1096
TEST(in_utc_timezone) {
1✔
1097
        const char *tz = getenv("TZ");
1✔
1098

1099
        assert_se(setenv("TZ", ":UTC", 1) >= 0);
1✔
1100
        assert_se(in_utc_timezone());
1✔
1101
        ASSERT_STREQ(tzname[0], "UTC");
1✔
1102
        ASSERT_STREQ(tzname[1], "UTC");
1✔
1103
        assert_se(timezone == 0);
1✔
1104
        assert_se(daylight == 0);
1✔
1105

1106
        assert_se(setenv("TZ", ":Europe/Berlin", 1) >= 0);
1✔
1107
        assert_se(!in_utc_timezone());
1✔
1108
        ASSERT_STREQ(tzname[0], "CET");
1✔
1109
        ASSERT_STREQ(tzname[1], "CEST");
1✔
1110

1111
        assert_se(set_unset_env("TZ", tz, true) == 0);
1✔
1112
        tzset();
1✔
1113
}
1✔
1114

1115
TEST(map_clock_usec) {
1✔
1116
        usec_t nowr, x, y, z;
1✔
1117

1118
        x = nowr = now(CLOCK_REALTIME); /* right now */
1✔
1119
        y = map_clock_usec(x, CLOCK_REALTIME, CLOCK_MONOTONIC);
1✔
1120
        z = map_clock_usec(y, CLOCK_MONOTONIC, CLOCK_REALTIME);
1✔
1121
        /* 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 */
1122

1123
        assert_se((z > x ? z - x : x - z) < USEC_PER_HOUR);
1✔
1124

1125
        assert_se(nowr < USEC_INFINITY - USEC_PER_DAY*7); /* overflow check */
1✔
1126
        x = nowr + USEC_PER_DAY*7; /* 1 week from now */
1✔
1127
        y = map_clock_usec(x, CLOCK_REALTIME, CLOCK_MONOTONIC);
1✔
1128
        assert_se(timestamp_is_set(y));
1✔
1129
        z = map_clock_usec(y, CLOCK_MONOTONIC, CLOCK_REALTIME);
1✔
1130
        assert_se(timestamp_is_set(z));
1✔
1131
        assert_se((z > x ? z - x : x - z) < USEC_PER_HOUR);
1✔
1132

1133
        assert_se(nowr > USEC_PER_DAY * 7); /* underflow check */
1✔
1134
        x = nowr - USEC_PER_DAY*7; /* 1 week ago */
1✔
1135
        y = map_clock_usec(x, CLOCK_REALTIME, CLOCK_MONOTONIC);
1✔
1136
        if (y != 0) { /* might underflow if machine is not up long enough for the monotonic clock to be beyond 1w */
1✔
1137
                assert_se(y < USEC_INFINITY);
×
1138
                z = map_clock_usec(y, CLOCK_MONOTONIC, CLOCK_REALTIME);
×
1139
                assert_se(timestamp_is_set(z));
×
1140
                assert_se((z > x ? z - x : x - z) < USEC_PER_HOUR);
×
1141
        }
1142
}
1✔
1143

1144
static void test_timezone_offset_change_one(const char *utc, const char *pretty) {
14✔
1145
        usec_t x, y, z;
14✔
1146
        char *s;
14✔
1147

1148
        assert_se(parse_timestamp(utc, &x) >= 0);
14✔
1149

1150
        s = FORMAT_TIMESTAMP_STYLE(x, TIMESTAMP_UTC);
14✔
1151
        assert_se(parse_timestamp(s, &y) >= 0);
14✔
1152
        log_debug("%s -> " USEC_FMT " -> %s -> " USEC_FMT, utc, x, s, y);
14✔
1153
        ASSERT_STREQ(s, utc);
14✔
1154
        assert_se(x == y);
14✔
1155

1156
        assert_se(parse_timestamp(pretty, &y) >= 0);
14✔
1157
        s = FORMAT_TIMESTAMP_STYLE(y, TIMESTAMP_PRETTY);
14✔
1158
        assert_se(parse_timestamp(s, &z) >= 0);
14✔
1159
        log_debug("%s -> " USEC_FMT " -> %s -> " USEC_FMT, pretty, y, s, z);
14✔
1160
        ASSERT_STREQ(s, pretty);
14✔
1161
        assert_se(x == y);
14✔
1162
        assert_se(x == z);
14✔
1163
}
14✔
1164

1165
TEST(timezone_offset_change) {
1✔
1166
        const char *tz = getenv("TZ");
1✔
1167

1168
        /* See issue #26370. */
1169

1170
        if (timezone_is_valid("Africa/Casablanca", LOG_DEBUG)) {
1✔
1171
                assert_se(setenv("TZ", ":Africa/Casablanca", 1) >= 0);
1✔
1172
                tzset();
1✔
1173
                log_debug("Africa/Casablanca: tzname[0]=%s, tzname[1]=%s", strempty(tzname[0]), strempty(tzname[1]));
1✔
1174

1175
                test_timezone_offset_change_one("Sun 2015-10-25 01:59:59 UTC", "Sun 2015-10-25 02:59:59 +01");
1✔
1176
                test_timezone_offset_change_one("Sun 2015-10-25 02:00:00 UTC", "Sun 2015-10-25 02:00:00 +00");
1✔
1177
                test_timezone_offset_change_one("Sun 2018-06-17 01:59:59 UTC", "Sun 2018-06-17 01:59:59 +00");
1✔
1178
                test_timezone_offset_change_one("Sun 2018-06-17 02:00:00 UTC", "Sun 2018-06-17 03:00:00 +01");
1✔
1179
                test_timezone_offset_change_one("Sun 2018-10-28 01:59:59 UTC", "Sun 2018-10-28 02:59:59 +01");
1✔
1180
                test_timezone_offset_change_one("Sun 2018-10-28 02:00:00 UTC", "Sun 2018-10-28 03:00:00 +01");
1✔
1181
        }
1182

1183
        if (timezone_is_valid("Asia/Atyrau", LOG_DEBUG)) {
1✔
1184
                assert_se(setenv("TZ", ":Asia/Atyrau", 1) >= 0);
1✔
1185
                tzset();
1✔
1186
                log_debug("Asia/Atyrau: tzname[0]=%s, tzname[1]=%s", strempty(tzname[0]), strempty(tzname[1]));
1✔
1187

1188
                test_timezone_offset_change_one("Sat 2004-03-27 21:59:59 UTC", "Sun 2004-03-28 01:59:59 +04");
1✔
1189
                test_timezone_offset_change_one("Sat 2004-03-27 22:00:00 UTC", "Sun 2004-03-28 03:00:00 +05");
1✔
1190
                test_timezone_offset_change_one("Sat 2004-10-30 21:59:59 UTC", "Sun 2004-10-31 02:59:59 +05");
1✔
1191
                test_timezone_offset_change_one("Sat 2004-10-30 22:00:00 UTC", "Sun 2004-10-31 03:00:00 +05");
1✔
1192
        }
1193

1194
        if (timezone_is_valid("Chile/EasterIsland", LOG_DEBUG)) {
1✔
1195
                assert_se(setenv("TZ", ":Chile/EasterIsland", 1) >= 0);
1✔
1196
                tzset();
1✔
1197
                log_debug("Chile/EasterIsland: tzname[0]=%s, tzname[1]=%s", strempty(tzname[0]), strempty(tzname[1]));
1✔
1198

1199
                test_timezone_offset_change_one("Sun 1981-10-11 03:59:59 UTC", "Sat 1981-10-10 20:59:59 -07");
1✔
1200
                test_timezone_offset_change_one("Sun 1981-10-11 04:00:00 UTC", "Sat 1981-10-10 22:00:00 -06");
1✔
1201
                test_timezone_offset_change_one("Sun 1982-03-14 02:59:59 UTC", "Sat 1982-03-13 20:59:59 -06");
1✔
1202
                test_timezone_offset_change_one("Sun 1982-03-14 03:00:00 UTC", "Sat 1982-03-13 21:00:00 -06");
1✔
1203
        }
1204

1205
        assert_se(set_unset_env("TZ", tz, true) == 0);
1✔
1206
        tzset();
1✔
1207
}
1✔
1208

1209
static usec_t absdiff(usec_t a, usec_t b) {
2✔
1210
        return a > b ? a - b : b - a;
2✔
1211
}
1212

1213
TEST(mktime_or_timegm_usec) {
1✔
1214

1215
        usec_t n = now(CLOCK_REALTIME), m;
1✔
1216
        struct tm tm;
1✔
1217

1218
        assert_se(localtime_or_gmtime_usec(n, /* utc= */ false, &tm) >= 0);
1✔
1219
        assert_se(mktime_or_timegm_usec(&tm, /* utc= */ false, &m) >= 0);
1✔
1220
        assert_se(absdiff(n, m) < 2 * USEC_PER_DAY);
1✔
1221

1222
        assert_se(localtime_or_gmtime_usec(n, /* utc= */ true, &tm) >= 0);
1✔
1223
        assert_se(mktime_or_timegm_usec(&tm, /* utc= */ true, &m) >= 0);
1✔
1224
        assert_se(absdiff(n, m) < USEC_PER_SEC);
1✔
1225

1226
        /* This definitely should fail, because we refuse dates before the UNIX epoch */
1227
        tm = (struct tm) {
1✔
1228
                .tm_mday = 15,
1229
                .tm_mon = 11,
1230
                .tm_year = 1969 - 1900,
1231
        };
1232

1233
        assert_se(mktime_or_timegm_usec(&tm, /* utc= */ true, NULL) == -ERANGE);
1✔
1234
}
1✔
1235

1236
static int intro(void) {
1✔
1237
        /* Tests have hard-coded results that do not expect a specific timezone to be set by the caller */
1238
        assert_se(unsetenv("TZ") >= 0);
1✔
1239

1240
        log_info("realtime=" USEC_FMT "\n"
1✔
1241
                 "monotonic=" USEC_FMT "\n"
1242
                 "boottime=" USEC_FMT "\n",
1243
                 now(CLOCK_REALTIME),
1244
                 now(CLOCK_MONOTONIC),
1245
                 now(CLOCK_BOOTTIME));
1246

1247
        /* Ensure time_t is signed */
1248
        assert_cc((time_t) -1 < (time_t) 1);
1✔
1249

1250
        /* Ensure TIME_T_MAX works correctly */
1251
        uintmax_t x = TIME_T_MAX;
1✔
1252
        x++;
1✔
1253
        assert_se((time_t) x < 0);
1✔
1254

1255
        return EXIT_SUCCESS;
1✔
1256
}
1257

1258
DEFINE_TEST_MAIN_WITH_INTRO(LOG_INFO, intro);
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc