xref: /netbsd-src/external/mpl/bind/dist/lib/isc/time.c (revision bcda20f65a8566e103791ec395f7f499ef322704)
1 /*	$NetBSD: time.c,v 1.4 2025/01/26 16:25:39 christos Exp $	*/
2 
3 /*
4  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5  *
6  * SPDX-License-Identifier: MPL-2.0
7  *
8  * This Source Code Form is subject to the terms of the Mozilla Public
9  * License, v. 2.0. If a copy of the MPL was not distributed with this
10  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
11  *
12  * See the COPYRIGHT file distributed with this work for additional
13  * information regarding copyright ownership.
14  */
15 
16 /*! \file */
17 
18 #include <errno.h>
19 #include <inttypes.h>
20 #include <limits.h>
21 #include <stdbool.h>
22 #include <stdlib.h>
23 #include <sys/time.h> /* Required for struct timeval on some platforms. */
24 #include <syslog.h>
25 #include <time.h>
26 
27 #include <isc/log.h>
28 #include <isc/overflow.h>
29 #include <isc/strerr.h>
30 #include <isc/string.h>
31 #include <isc/time.h>
32 #include <isc/tm.h>
33 #include <isc/util.h>
34 
35 #if defined(CLOCK_REALTIME)
36 #define CLOCKSOURCE_HIRES CLOCK_REALTIME
37 #endif /* #if defined(CLOCK_REALTIME) */
38 
39 #if defined(CLOCK_REALTIME_COARSE)
40 #define CLOCKSOURCE CLOCK_REALTIME_COARSE
41 #elif defined(CLOCK_REALTIME_FAST)
42 #define CLOCKSOURCE CLOCK_REALTIME_FAST
43 #else /* if defined(CLOCK_REALTIME_COARSE) */
44 #define CLOCKSOURCE CLOCK_REALTIME
45 #endif /* if defined(CLOCK_REALTIME_COARSE) */
46 
47 #if !defined(CLOCKSOURCE_HIRES)
48 #define CLOCKSOURCE_HIRES CLOCKSOURCE
49 #endif /* #ifndef CLOCKSOURCE_HIRES */
50 
51 #if !defined(UNIT_TESTING)
52 static const isc_time_t epoch = { 0, 0 };
53 const isc_time_t *const isc_time_epoch = &epoch;
54 #endif
55 
56 void
57 isc_time_set(isc_time_t *t, unsigned int seconds, unsigned int nanoseconds) {
58 	REQUIRE(t != NULL);
59 	REQUIRE(nanoseconds < NS_PER_SEC);
60 
61 	t->seconds = seconds;
62 	t->nanoseconds = nanoseconds;
63 }
64 
65 void
66 isc_time_settoepoch(isc_time_t *t) {
67 	REQUIRE(t != NULL);
68 
69 	t->seconds = 0;
70 	t->nanoseconds = 0;
71 }
72 
73 bool
74 isc_time_isepoch(const isc_time_t *t) {
75 	REQUIRE(t != NULL);
76 	INSIST(t->nanoseconds < NS_PER_SEC);
77 
78 	if (t->seconds == 0 && t->nanoseconds == 0) {
79 		return true;
80 	}
81 
82 	return false;
83 }
84 
85 static isc_time_t
86 time_now(clockid_t clock) {
87 	isc_time_t t;
88 	struct timespec ts;
89 
90 	RUNTIME_CHECK(clock_gettime(clock, &ts) == 0);
91 	INSIST(ts.tv_sec >= 0 && ts.tv_nsec >= 0 &&
92 	       ts.tv_nsec < (long)NS_PER_SEC);
93 
94 	/*
95 	 * Ensure the tv_sec value fits in t->seconds.
96 	 */
97 	INSIST(sizeof(ts.tv_sec) <= sizeof(t.seconds) ||
98 	       ((ts.tv_sec | (unsigned int)-1) ^ (unsigned int)-1) == 0U);
99 
100 	t.seconds = ts.tv_sec;
101 	t.nanoseconds = ts.tv_nsec;
102 
103 	return t;
104 }
105 
106 isc_time_t
107 isc_time_now_hires(void) {
108 	return time_now(CLOCKSOURCE_HIRES);
109 }
110 
111 isc_time_t
112 isc_time_now(void) {
113 	return time_now(CLOCKSOURCE);
114 }
115 
116 isc_nanosecs_t
117 isc_time_monotonic(void) {
118 	struct timespec ts;
119 
120 	RUNTIME_CHECK(clock_gettime(CLOCK_MONOTONIC, &ts) != -1);
121 
122 	isc_time_t time = {
123 		.seconds = ts.tv_sec,
124 		.nanoseconds = ts.tv_nsec,
125 	};
126 
127 	return isc_nanosecs_fromtime(time);
128 }
129 
130 isc_result_t
131 isc_time_nowplusinterval(isc_time_t *t, const isc_interval_t *i) {
132 	struct timespec ts;
133 
134 	REQUIRE(t != NULL);
135 	REQUIRE(i != NULL);
136 	INSIST(i->nanoseconds < NS_PER_SEC);
137 
138 	if (clock_gettime(CLOCKSOURCE, &ts) == -1) {
139 		UNEXPECTED_SYSERROR(errno, "clock_gettime()");
140 		return ISC_R_UNEXPECTED;
141 	}
142 
143 	if (ts.tv_sec < 0 || ts.tv_nsec < 0 || ts.tv_nsec >= (long)NS_PER_SEC) {
144 		return ISC_R_UNEXPECTED;
145 	}
146 
147 	/*
148 	 * Ensure the resulting seconds value fits in the size of an
149 	 * unsigned int.  (It is written this way as a slight optimization;
150 	 * note that even if both values == INT_MAX, then when added
151 	 * and getting another 1 added below the result is UINT_MAX.)
152 	 */
153 	if ((ts.tv_sec > INT_MAX || i->seconds > INT_MAX) &&
154 	    ((long long)ts.tv_sec + i->seconds > UINT_MAX))
155 	{
156 		return ISC_R_RANGE;
157 	}
158 
159 	t->seconds = ts.tv_sec + i->seconds;
160 	t->nanoseconds = ts.tv_nsec + i->nanoseconds;
161 	if (t->nanoseconds >= NS_PER_SEC) {
162 		t->seconds++;
163 		t->nanoseconds -= NS_PER_SEC;
164 	}
165 
166 	return ISC_R_SUCCESS;
167 }
168 
169 int
170 isc_time_compare(const isc_time_t *t1, const isc_time_t *t2) {
171 	REQUIRE(t1 != NULL && t2 != NULL);
172 	INSIST(t1->nanoseconds < NS_PER_SEC && t2->nanoseconds < NS_PER_SEC);
173 
174 	if (t1->seconds < t2->seconds) {
175 		return -1;
176 	}
177 	if (t1->seconds > t2->seconds) {
178 		return 1;
179 	}
180 	if (t1->nanoseconds < t2->nanoseconds) {
181 		return -1;
182 	}
183 	if (t1->nanoseconds > t2->nanoseconds) {
184 		return 1;
185 	}
186 	return 0;
187 }
188 
189 isc_result_t
190 isc_time_add(const isc_time_t *t, const isc_interval_t *i, isc_time_t *result) {
191 	REQUIRE(t != NULL && i != NULL && result != NULL);
192 	REQUIRE(t->nanoseconds < NS_PER_SEC && i->nanoseconds < NS_PER_SEC);
193 
194 	/* Seconds */
195 	if (ISC_OVERFLOW_ADD(t->seconds, i->seconds, &result->seconds)) {
196 		return ISC_R_RANGE;
197 	}
198 
199 	/* Nanoseconds */
200 	result->nanoseconds = t->nanoseconds + i->nanoseconds;
201 	if (result->nanoseconds >= NS_PER_SEC) {
202 		if (result->seconds == UINT_MAX) {
203 			return ISC_R_RANGE;
204 		}
205 		result->nanoseconds -= NS_PER_SEC;
206 		result->seconds++;
207 	}
208 
209 	return ISC_R_SUCCESS;
210 }
211 
212 isc_result_t
213 isc_time_subtract(const isc_time_t *t, const isc_interval_t *i,
214 		  isc_time_t *result) {
215 	REQUIRE(t != NULL && i != NULL && result != NULL);
216 	REQUIRE(t->nanoseconds < NS_PER_SEC && i->nanoseconds < NS_PER_SEC);
217 
218 	/* Seconds */
219 	if (ISC_OVERFLOW_SUB(t->seconds, i->seconds, &result->seconds)) {
220 		return ISC_R_RANGE;
221 	}
222 
223 	/* Nanoseconds */
224 	if (t->nanoseconds >= i->nanoseconds) {
225 		result->nanoseconds = t->nanoseconds - i->nanoseconds;
226 	} else {
227 		if (result->seconds == 0) {
228 			return ISC_R_RANGE;
229 		}
230 		result->seconds--;
231 		result->nanoseconds = NS_PER_SEC + t->nanoseconds -
232 				      i->nanoseconds;
233 	}
234 
235 	return ISC_R_SUCCESS;
236 }
237 
238 uint64_t
239 isc_time_microdiff(const isc_time_t *t1, const isc_time_t *t2) {
240 	uint64_t i1, i2, i3;
241 
242 	REQUIRE(t1 != NULL && t2 != NULL);
243 	INSIST(t1->nanoseconds < NS_PER_SEC && t2->nanoseconds < NS_PER_SEC);
244 
245 	i1 = (uint64_t)t1->seconds * NS_PER_SEC + t1->nanoseconds;
246 	i2 = (uint64_t)t2->seconds * NS_PER_SEC + t2->nanoseconds;
247 
248 	if (i1 <= i2) {
249 		return 0;
250 	}
251 
252 	i3 = i1 - i2;
253 
254 	/*
255 	 * Convert to microseconds.
256 	 */
257 	i3 /= NS_PER_US;
258 
259 	return i3;
260 }
261 
262 uint32_t
263 isc_time_seconds(const isc_time_t *t) {
264 	REQUIRE(t != NULL);
265 	INSIST(t->nanoseconds < NS_PER_SEC);
266 
267 	return (uint32_t)t->seconds;
268 }
269 
270 isc_result_t
271 isc_time_secondsastimet(const isc_time_t *t, time_t *secondsp) {
272 	time_t seconds;
273 
274 	REQUIRE(t != NULL);
275 	INSIST(t->nanoseconds < NS_PER_SEC);
276 
277 	/*
278 	 * Ensure that the number of seconds represented by t->seconds
279 	 * can be represented by a time_t.  Since t->seconds is an
280 	 * unsigned int and since time_t is mostly opaque, this is
281 	 * trickier than it seems.  (This standardized opaqueness of
282 	 * time_t is *very* frustrating; time_t is not even limited to
283 	 * being an integral type.)
284 	 *
285 	 * The mission, then, is to avoid generating any kind of warning
286 	 * about "signed versus unsigned" while trying to determine if
287 	 * the unsigned int t->seconds is out range for tv_sec,
288 	 * which is pretty much only true if time_t is a signed integer
289 	 * of the same size as the return value of isc_time_seconds.
290 	 *
291 	 * If the paradox in the if clause below is true, t->seconds is
292 	 * out of range for time_t.
293 	 */
294 	seconds = (time_t)t->seconds;
295 
296 	INSIST(sizeof(unsigned int) == sizeof(uint32_t));
297 	INSIST(sizeof(time_t) >= sizeof(uint32_t));
298 
299 	if (t->seconds > (~0U >> 1) && seconds <= (time_t)(~0U >> 1)) {
300 		return ISC_R_RANGE;
301 	}
302 
303 	*secondsp = seconds;
304 
305 	return ISC_R_SUCCESS;
306 }
307 
308 uint32_t
309 isc_time_nanoseconds(const isc_time_t *t) {
310 	REQUIRE(t != NULL);
311 
312 	ENSURE(t->nanoseconds < NS_PER_SEC);
313 
314 	return (uint32_t)t->nanoseconds;
315 }
316 
317 uint32_t
318 isc_time_miliseconds(const isc_time_t *t) {
319 	REQUIRE(t != NULL);
320 	INSIST(t->nanoseconds < NS_PER_SEC);
321 
322 	return (t->seconds * MS_PER_SEC) + (t->nanoseconds / NS_PER_MS);
323 }
324 
325 void
326 isc_time_formattimestamp(const isc_time_t *t, char *buf, unsigned int len) {
327 	time_t now;
328 	unsigned int flen;
329 	struct tm tm;
330 
331 	REQUIRE(t != NULL);
332 	INSIST(t->nanoseconds < NS_PER_SEC);
333 	REQUIRE(buf != NULL);
334 	REQUIRE(len > 0);
335 
336 	now = (time_t)t->seconds;
337 	flen = strftime(buf, len, "%d-%b-%Y %X", localtime_r(&now, &tm));
338 	INSIST(flen < len);
339 	if (flen != 0) {
340 		snprintf(buf + flen, len - flen, ".%03u",
341 			 t->nanoseconds / NS_PER_MS);
342 	} else {
343 		strlcpy(buf, "99-Bad-9999 99:99:99.999", len);
344 	}
345 }
346 
347 void
348 isc_time_formathttptimestamp(const isc_time_t *t, char *buf, unsigned int len) {
349 	time_t now;
350 	unsigned int flen;
351 	struct tm tm;
352 
353 	REQUIRE(t != NULL);
354 	INSIST(t->nanoseconds < NS_PER_SEC);
355 	REQUIRE(buf != NULL);
356 	REQUIRE(len > 0);
357 
358 	/*
359 	 * 5 spaces, 1 comma, 3 GMT, 2 %d, 4 %Y, 8 %H:%M:%S, 3+ %a, 3+
360 	 * %b (29+)
361 	 */
362 	now = (time_t)t->seconds;
363 	flen = strftime(buf, len, "%a, %d %b %Y %H:%M:%S GMT",
364 			gmtime_r(&now, &tm));
365 	INSIST(flen < len);
366 }
367 
368 isc_result_t
369 isc_time_parsehttptimestamp(char *buf, isc_time_t *t) {
370 	struct tm t_tm;
371 	time_t when;
372 	char *p;
373 
374 	REQUIRE(buf != NULL);
375 	REQUIRE(t != NULL);
376 
377 	p = isc_tm_strptime(buf, "%a, %d %b %Y %H:%M:%S", &t_tm);
378 	if (p == NULL) {
379 		return ISC_R_UNEXPECTED;
380 	}
381 	when = isc_tm_timegm(&t_tm);
382 	if (when == -1) {
383 		return ISC_R_UNEXPECTED;
384 	}
385 	isc_time_set(t, when, 0);
386 	return ISC_R_SUCCESS;
387 }
388 
389 void
390 isc_time_formatISO8601L(const isc_time_t *t, char *buf, unsigned int len) {
391 	time_t now;
392 	unsigned int flen;
393 	struct tm tm;
394 
395 	REQUIRE(t != NULL);
396 	INSIST(t->nanoseconds < NS_PER_SEC);
397 	REQUIRE(buf != NULL);
398 	REQUIRE(len > 0);
399 
400 	now = (time_t)t->seconds;
401 	flen = strftime(buf, len, "%Y-%m-%dT%H:%M:%S", localtime_r(&now, &tm));
402 	INSIST(flen < len);
403 }
404 
405 void
406 isc_time_formatISO8601Lms(const isc_time_t *t, char *buf, unsigned int len) {
407 	time_t now;
408 	unsigned int flen;
409 	struct tm tm;
410 
411 	REQUIRE(t != NULL);
412 	INSIST(t->nanoseconds < NS_PER_SEC);
413 	REQUIRE(buf != NULL);
414 	REQUIRE(len > 0);
415 
416 	now = (time_t)t->seconds;
417 	flen = strftime(buf, len, "%Y-%m-%dT%H:%M:%S", localtime_r(&now, &tm));
418 	INSIST(flen < len);
419 	if (flen > 0U && len - flen >= 6) {
420 		snprintf(buf + flen, len - flen, ".%03u",
421 			 t->nanoseconds / NS_PER_MS);
422 	}
423 }
424 
425 void
426 isc_time_formatISO8601Lus(const isc_time_t *t, char *buf, unsigned int len) {
427 	time_t now;
428 	unsigned int flen;
429 	struct tm tm;
430 
431 	REQUIRE(t != NULL);
432 	INSIST(t->nanoseconds < NS_PER_SEC);
433 	REQUIRE(buf != NULL);
434 	REQUIRE(len > 0);
435 
436 	now = (time_t)t->seconds;
437 	flen = strftime(buf, len, "%Y-%m-%dT%H:%M:%S", localtime_r(&now, &tm));
438 	INSIST(flen < len);
439 	if (flen > 0U && len - flen >= 6) {
440 		snprintf(buf + flen, len - flen, ".%06u",
441 			 t->nanoseconds / NS_PER_US);
442 	}
443 }
444 
445 void
446 isc_time_formatISO8601(const isc_time_t *t, char *buf, unsigned int len) {
447 	time_t now;
448 	unsigned int flen;
449 	struct tm tm;
450 
451 	REQUIRE(t != NULL);
452 	INSIST(t->nanoseconds < NS_PER_SEC);
453 	REQUIRE(buf != NULL);
454 	REQUIRE(len > 0);
455 
456 	now = (time_t)t->seconds;
457 	flen = strftime(buf, len, "%Y-%m-%dT%H:%M:%SZ", gmtime_r(&now, &tm));
458 	INSIST(flen < len);
459 }
460 
461 void
462 isc_time_formatISO8601ms(const isc_time_t *t, char *buf, unsigned int len) {
463 	time_t now;
464 	unsigned int flen;
465 	struct tm tm;
466 
467 	REQUIRE(t != NULL);
468 	INSIST(t->nanoseconds < NS_PER_SEC);
469 	REQUIRE(buf != NULL);
470 	REQUIRE(len > 0);
471 
472 	now = (time_t)t->seconds;
473 	flen = strftime(buf, len, "%Y-%m-%dT%H:%M:%SZ", gmtime_r(&now, &tm));
474 	INSIST(flen < len);
475 	if (flen > 0U && len - flen >= 5) {
476 		flen -= 1; /* rewind one character (Z) */
477 		snprintf(buf + flen, len - flen, ".%03uZ",
478 			 t->nanoseconds / NS_PER_MS);
479 	}
480 }
481 
482 void
483 isc_time_formatISO8601us(const isc_time_t *t, char *buf, unsigned int len) {
484 	time_t now;
485 	unsigned int flen;
486 	struct tm tm;
487 
488 	REQUIRE(t != NULL);
489 	INSIST(t->nanoseconds < NS_PER_SEC);
490 	REQUIRE(buf != NULL);
491 	REQUIRE(len > 0);
492 
493 	now = (time_t)t->seconds;
494 	flen = strftime(buf, len, "%Y-%m-%dT%H:%M:%SZ", gmtime_r(&now, &tm));
495 	INSIST(flen < len);
496 	if (flen > 0U && len - flen >= 5) {
497 		flen -= 1; /* rewind one character (Z) */
498 		snprintf(buf + flen, len - flen, ".%06uZ",
499 			 t->nanoseconds / NS_PER_US);
500 	}
501 }
502 
503 void
504 isc_time_formatshorttimestamp(const isc_time_t *t, char *buf,
505 			      unsigned int len) {
506 	time_t now;
507 	unsigned int flen;
508 	struct tm tm;
509 
510 	REQUIRE(t != NULL);
511 	INSIST(t->nanoseconds < NS_PER_SEC);
512 	REQUIRE(buf != NULL);
513 	REQUIRE(len > 0);
514 
515 	now = (time_t)t->seconds;
516 	flen = strftime(buf, len, "%Y%m%d%H%M%S", gmtime_r(&now, &tm));
517 	INSIST(flen < len);
518 	if (flen > 0U && len - flen >= 5) {
519 		snprintf(buf + flen, len - flen, "%03u",
520 			 t->nanoseconds / NS_PER_MS);
521 	}
522 }
523