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