1 /* $NetBSD: time.h,v 1.4 2025/01/26 16:25:43 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 #pragma once 17 18 /*! \file */ 19 20 #include <inttypes.h> 21 #include <time.h> 22 23 #include <isc/attributes.h> 24 #include <isc/lang.h> 25 #include <isc/types.h> 26 27 /* 28 * Define various time conversion constants. 29 */ 30 ISC_CONSTEXPR unsigned int MS_PER_SEC = 1000; 31 ISC_CONSTEXPR unsigned int US_PER_MS = 1000; 32 ISC_CONSTEXPR unsigned int NS_PER_US = 1000; 33 ISC_CONSTEXPR unsigned int US_PER_SEC = 1000 * 1000; 34 ISC_CONSTEXPR unsigned int NS_PER_MS = 1000 * 1000; 35 ISC_CONSTEXPR unsigned int NS_PER_SEC = 1000 * 1000 * 1000; 36 37 /* 38 * ISC_FORMATHTTPTIMESTAMP_SIZE needs to be 30 in C locale and potentially 39 * more for other locales to handle longer national abbreviations when 40 * expanding strftime's %a and %b. 41 */ 42 #define ISC_FORMATHTTPTIMESTAMP_SIZE 50 43 44 /* 45 * Semantic shims to distinguish between relative and absolute time 46 */ 47 #define isc_interval_zero isc_time_epoch 48 #define isc_interval_t isc_time_t 49 50 ISC_LANG_BEGINDECLS 51 52 #define isc_interval_set(i, seconds, nanoseconds) \ 53 isc_time_set((isc_time_t *)i, seconds, nanoseconds) 54 /*%< 55 * Set 'i' to a value representing an interval of 'seconds' seconds and 56 * 'nanoseconds' nanoseconds, suitable for use in isc_time_add() and 57 * isc_time_subtract(). 58 * 59 * Requires: 60 * 61 *\li 't' is a valid pointer. 62 *\li nanoseconds < 1000000000. 63 */ 64 65 #define isc_interval_iszero(i) isc_time_isepoch((const isc_time_t *)i) 66 /*%< 67 * Returns true iff. 'i' is the zero interval. 68 * 69 * Requires: 70 * 71 *\li 'i' is a valid pointer. 72 */ 73 74 #define isc_interval_ms(i) isc_time_miliseconds((const isc_time_t *)i) 75 /*%< 76 * Returns interval 'i' expressed as a number of milliseconds. 77 * 78 * Requires: 79 * 80 *\li 'i' is a valid pointer. 81 */ 82 83 #define isc_interval_fromnanosecs(ns) isc_time_fromnanosecs(ns) 84 #define isc_interval_tonanosecs(i) isc_time_tonanosecs(i) 85 86 /*** 87 *** Absolute Times 88 ***/ 89 90 /*% 91 * A linear count of nanoseconds. 92 * 93 * 64 bits of nanoseconds is more than 500 years. 94 */ 95 typedef uint64_t isc_nanosecs_t; 96 97 /*% 98 * Convert linear nanoseconds to an isc_time_t 99 */ 100 #define isc_nanosecs_fromtime(time) \ 101 (NS_PER_SEC * (isc_nanosecs_t)(time).seconds + (time).nanoseconds) 102 103 /*% 104 * Construct an isc_time_t from linear nanoseconds 105 */ 106 #define isc_time_fromnanosecs(ns) \ 107 ((isc_time_t){ \ 108 .seconds = (ns) / NS_PER_SEC, \ 109 .nanoseconds = (ns) % NS_PER_SEC, \ 110 }) 111 112 /*% 113 * The contents of this structure are private, and MUST NOT be accessed 114 * directly by callers. 115 * 116 * The contents are exposed only to allow callers to avoid dynamic allocation. 117 */ 118 119 struct isc_time { 120 unsigned int seconds; 121 unsigned int nanoseconds; 122 }; 123 124 extern const isc_time_t *const isc_time_epoch; 125 126 void 127 isc_time_set(isc_time_t *t, unsigned int seconds, unsigned int nanoseconds); 128 /*%< 129 * Set 't' to a value which represents the given number of seconds and 130 * nanoseconds since 00:00:00 January 1, 1970, UTC. 131 * 132 * Notes: 133 *\li The Unix version of this call is equivalent to: 134 *\code 135 * isc_time_settoepoch(t); 136 * isc_interval_set(i, seconds, nanoseconds); 137 * isc_time_add(t, i, t); 138 *\endcode 139 * 140 * Requires: 141 *\li 't' is a valid pointer. 142 *\li nanoseconds < 1000000000. 143 */ 144 145 void 146 isc_time_settoepoch(isc_time_t *t); 147 /*%< 148 * Set 't' to the time of the epoch. 149 * 150 * Notes: 151 *\li The date of the epoch is platform-dependent. 152 * 153 * Requires: 154 * 155 *\li 't' is a valid pointer. 156 */ 157 158 bool 159 isc_time_isepoch(const isc_time_t *t); 160 /*%< 161 * Returns true iff. 't' is the epoch ("time zero"). 162 * 163 * Requires: 164 * 165 *\li 't' is a valid pointer. 166 */ 167 168 isc_nanosecs_t 169 isc_time_monotonic(void); 170 /*%< 171 * Returns the system's monotonic time in linear nanoseconds. 172 */ 173 174 isc_time_t 175 isc_time_now(void); 176 /*%< 177 * Set 't' to the current absolute time. 178 * 179 * Requires: 180 * 181 *\li 't' is a valid pointer. 182 * 183 * Returns: 184 * 185 *\li Success 186 *\li Unexpected error 187 * Getting the time from the system failed. 188 *\li Out of range 189 * The time from the system is too large to be represented 190 * in the current definition of isc_time_t. 191 */ 192 193 isc_time_t 194 isc_time_now_hires(void); 195 /*%< 196 * Set 't' to the current absolute time. Uses higher resolution clocks 197 * recommended when microsecond accuracy is required. 198 * 199 * Requires: 200 * 201 *\li 't' is a valid pointer. 202 * 203 * Returns: 204 * 205 *\li Success 206 *\li Unexpected error 207 * Getting the time from the system failed. 208 *\li Out of range 209 * The time from the system is too large to be represented 210 * in the current definition of isc_time_t. 211 */ 212 213 isc_result_t 214 isc_time_nowplusinterval(isc_time_t *t, const isc_interval_t *i); 215 /*%< 216 * Set *t to the current absolute time + i. 217 * 218 * Note: 219 *\li This call is equivalent to: 220 * 221 *\code 222 * isc_time_now(t); 223 * isc_time_add(t, i, t); 224 *\endcode 225 * 226 * Requires: 227 * 228 *\li 't' and 'i' are valid pointers. 229 * 230 * Returns: 231 * 232 *\li Success 233 *\li Unexpected error 234 * Getting the time from the system failed. 235 *\li Out of range 236 * The interval added to the time from the system is too large to 237 * be represented in the current definition of isc_time_t. 238 */ 239 240 int 241 isc_time_compare(const isc_time_t *t1, const isc_time_t *t2); 242 /*%< 243 * Compare the times referenced by 't1' and 't2' 244 * 245 * Requires: 246 * 247 *\li 't1' and 't2' are valid pointers. 248 * 249 * Returns: 250 * 251 *\li -1 t1 < t2 (comparing times, not pointers) 252 *\li 0 t1 = t2 253 *\li 1 t1 > t2 254 */ 255 256 isc_result_t 257 isc_time_add(const isc_time_t *t, const isc_interval_t *i, isc_time_t *result); 258 /*%< 259 * Add 'i' to 't', storing the result in 'result'. 260 * 261 * Requires: 262 * 263 *\li 't', 'i', and 'result' are valid pointers. 264 * 265 * Returns: 266 *\li Success 267 *\li Out of range 268 * The interval added to the time is too large to 269 * be represented in the current definition of isc_time_t. 270 */ 271 272 isc_result_t 273 isc_time_subtract(const isc_time_t *t, const isc_interval_t *i, 274 isc_time_t *result); 275 /*%< 276 * Subtract 'i' from 't', storing the result in 'result'. 277 * 278 * Requires: 279 * 280 *\li 't', 'i', and 'result' are valid pointers. 281 * 282 * Returns: 283 *\li Success 284 *\li Out of range 285 * The interval is larger than the time since the epoch. 286 */ 287 288 uint64_t 289 isc_time_microdiff(const isc_time_t *t1, const isc_time_t *t2); 290 /*%< 291 * Find the difference in microseconds between time t1 and time t2. 292 * t2 is the subtrahend of t1; ie, difference = t1 - t2. 293 * 294 * Requires: 295 * 296 *\li 't1' and 't2' are valid pointers. 297 * 298 * Returns: 299 *\li The difference of t1 - t2, or 0 if t1 <= t2. 300 */ 301 302 uint32_t 303 isc_time_seconds(const isc_time_t *t); 304 /*%< 305 * Return the number of seconds since the epoch stored in a time structure. 306 * 307 * Requires: 308 * 309 *\li 't' is a valid pointer. 310 */ 311 312 isc_result_t 313 isc_time_secondsastimet(const isc_time_t *t, time_t *secondsp); 314 /*%< 315 * Ensure the number of seconds in an isc_time_t is representable by a time_t. 316 * 317 * Notes: 318 *\li The number of seconds stored in an isc_time_t might be larger 319 * than the number of seconds a time_t is able to handle. Since 320 * time_t is mostly opaque according to the ANSI/ISO standard 321 * (essentially, all you can be sure of is that it is an arithmetic type, 322 * not even necessarily integral), it can be tricky to ensure that 323 * the isc_time_t is in the range a time_t can handle. Use this 324 * function in place of isc_time_seconds() any time you need to set a 325 * time_t from an isc_time_t. 326 * 327 * Requires: 328 *\li 't' is a valid pointer. 329 * 330 * Returns: 331 *\li Success 332 *\li Out of range 333 */ 334 335 uint32_t 336 isc_time_nanoseconds(const isc_time_t *t); 337 /*%< 338 * Return the number of nanoseconds stored in a time structure. 339 * 340 * Notes: 341 *\li This is the number of nanoseconds in excess of the number 342 * of seconds since the epoch; it will always be less than one 343 * full second. 344 * 345 * Requires: 346 *\li 't' is a valid pointer. 347 * 348 * Ensures: 349 *\li The returned value is less than 1*10^9. 350 */ 351 352 uint32_t 353 isc_time_miliseconds(const isc_time_t *t); 354 /*%< 355 * Returns time 't' expressed as a number of milliseconds. 356 * 357 * Requires: 358 * 359 *\li 't' is a valid pointer. 360 */ 361 362 void 363 isc_time_formattimestamp(const isc_time_t *t, char *buf, unsigned int len); 364 /*%< 365 * Format the time 't' into the buffer 'buf' of length 'len', 366 * using a format like "30-Aug-2000 04:06:47.997" and the local time zone. 367 * If the text does not fit in the buffer, the result is indeterminate, 368 * but is always guaranteed to be null terminated. 369 * 370 * Requires: 371 *\li 'len' > 0 372 *\li 'buf' points to an array of at least len chars 373 * 374 */ 375 376 void 377 isc_time_formathttptimestamp(const isc_time_t *t, char *buf, unsigned int len); 378 /*%< 379 * Format the time 't' into the buffer 'buf' of length 'len', 380 * using a format like "Mon, 30 Aug 2000 04:06:47 GMT" 381 * If the text does not fit in the buffer, the result is indeterminate, 382 * but is always guaranteed to be null terminated. 383 * 384 * Requires: 385 *\li 'len' > 0 386 *\li 'buf' points to an array of at least len chars 387 * 388 */ 389 390 isc_result_t 391 isc_time_parsehttptimestamp(char *input, isc_time_t *t); 392 /*%< 393 * Parse the time in 'input' into the isc_time_t pointed to by 't', 394 * expecting a format like "Mon, 30 Aug 2000 04:06:47 GMT" 395 * 396 * Requires: 397 *\li 'buf' and 't' are not NULL. 398 */ 399 400 void 401 isc_time_formatISO8601L(const isc_time_t *t, char *buf, unsigned int len); 402 /*%< 403 * Format the time 't' into the buffer 'buf' of length 'len', 404 * using the ISO8601 format: "yyyy-mm-ddThh:mm:ss" 405 * If the text does not fit in the buffer, the result is indeterminate, 406 * but is always guaranteed to be null terminated. 407 * 408 * Requires: 409 *\li 'len' > 0 410 *\li 'buf' points to an array of at least len chars 411 * 412 */ 413 414 void 415 isc_time_formatISO8601Lms(const isc_time_t *t, char *buf, unsigned int len); 416 /*%< 417 * Format the time 't' into the buffer 'buf' of length 'len', 418 * using the ISO8601 format: "yyyy-mm-ddThh:mm:ss.sss" 419 * If the text does not fit in the buffer, the result is indeterminate, 420 * but is always guaranteed to be null terminated. 421 * 422 * Requires: 423 *\li 'len' > 0 424 *\li 'buf' points to an array of at least len chars 425 * 426 */ 427 428 void 429 isc_time_formatISO8601Lus(const isc_time_t *t, char *buf, unsigned int len); 430 /*%< 431 * Format the time 't' into the buffer 'buf' of length 'len', 432 * using the ISO8601 format: "yyyy-mm-ddThh:mm:ss.ssssss" 433 * If the text does not fit in the buffer, the result is indeterminate, 434 * but is always guaranteed to be null terminated. 435 * 436 * Requires: 437 *\li 'len' > 0 438 *\li 'buf' points to an array of at least len chars 439 * 440 */ 441 442 void 443 isc_time_formatISO8601(const isc_time_t *t, char *buf, unsigned int len); 444 /*%< 445 * Format the time 't' into the buffer 'buf' of length 'len', 446 * using the ISO8601 format: "yyyy-mm-ddThh:mm:ssZ" 447 * If the text does not fit in the buffer, the result is indeterminate, 448 * but is always guaranteed to be null terminated. 449 * 450 * Requires: 451 *\li 'len' > 0 452 *\li 'buf' points to an array of at least len chars 453 * 454 */ 455 456 void 457 isc_time_formatISO8601ms(const isc_time_t *t, char *buf, unsigned int len); 458 /*%< 459 * Format the time 't' into the buffer 'buf' of length 'len', 460 * using the ISO8601 format: "yyyy-mm-ddThh:mm:ss.sssZ" 461 * If the text does not fit in the buffer, the result is indeterminate, 462 * but is always guaranteed to be null terminated. 463 * 464 * Requires: 465 *\li 'len' > 0 466 *\li 'buf' points to an array of at least len chars 467 * 468 */ 469 470 void 471 isc_time_formatISO8601us(const isc_time_t *t, char *buf, unsigned int len); 472 /*%< 473 * Format the time 't' into the buffer 'buf' of length 'len', 474 * using the ISO8601 format: "yyyy-mm-ddThh:mm:ss.ssssssZ" 475 * If the text does not fit in the buffer, the result is indeterminate, 476 * but is always guaranteed to be null terminated. 477 * 478 * Requires: 479 *\li 'len' > 0 480 *\li 'buf' points to an array of at least len chars 481 * 482 */ 483 484 void 485 isc_time_formatshorttimestamp(const isc_time_t *t, char *buf, unsigned int len); 486 /*%< 487 * Format the time 't' into the buffer 'buf' of length 'len', 488 * using the format "yyyymmddhhmmsssss" useful for file timestamping. 489 * If the text does not fit in the buffer, the result is indeterminate, 490 * but is always guaranteed to be null terminated. 491 * 492 * Requires: 493 *\li 'len' > 0 494 *\li 'buf' points to an array of at least len chars 495 * 496 */ 497 498 ISC_LANG_ENDDECLS 499