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

systemd / systemd / 14815796853

02 May 2025 11:41AM UTC coverage: 72.24% (-0.003%) from 72.243%
14815796853

push

github

web-flow
Various changes to prepare for running IWYU on the repository (#37319)

These are various commits that were required to get things compiling
after running IWYU. I think all of them make sense on their own, hence
this split PR to merge them ahead of time.

81 of 96 new or added lines in 48 files covered. (84.38%)

209 existing lines in 39 files now uncovered.

297219 of 411432 relevant lines covered (72.24%)

693693.2 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) {
599✔
277
                r = verify_timezone(*zone, LOG_ERR);
598✔
278
                log_debug_errno(r, "verify_timezone(\"%s\"): %m", *zone);
598✔
279
                assert_se(r >= 0 || r == -ENOENT);
598✔
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✔
UNCOV
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