Home | History | Annotate | Line # | Download | only in isc
      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