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