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