1*eabc0478Schristos /* $NetBSD: time.c,v 1.2 2024/08/18 20:47:16 christos Exp $ */ 2897be3a4Schristos 3897be3a4Schristos /* 4897be3a4Schristos * Copyright (C) 2004-2008, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") 5897be3a4Schristos * Copyright (C) 1998-2001, 2003 Internet Software Consortium. 6897be3a4Schristos * 7897be3a4Schristos * Permission to use, copy, modify, and/or distribute this software for any 8897be3a4Schristos * purpose with or without fee is hereby granted, provided that the above 9897be3a4Schristos * copyright notice and this permission notice appear in all copies. 10897be3a4Schristos * 11897be3a4Schristos * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 12897be3a4Schristos * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 13897be3a4Schristos * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 14897be3a4Schristos * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 15897be3a4Schristos * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 16897be3a4Schristos * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17897be3a4Schristos * PERFORMANCE OF THIS SOFTWARE. 18897be3a4Schristos */ 19897be3a4Schristos 20897be3a4Schristos /* Id */ 21897be3a4Schristos 22897be3a4Schristos /*! \file */ 23897be3a4Schristos 24897be3a4Schristos #include <config.h> 25897be3a4Schristos 26897be3a4Schristos #include <errno.h> 27897be3a4Schristos #include <limits.h> 28897be3a4Schristos #include <syslog.h> 29897be3a4Schristos #include <time.h> 30897be3a4Schristos 31897be3a4Schristos #include <sys/time.h> /* Required for struct timeval on some platforms. */ 32897be3a4Schristos 33897be3a4Schristos #include <isc/log.h> 34897be3a4Schristos #include <isc/print.h> 35897be3a4Schristos #include <isc/strerror.h> 36897be3a4Schristos #include <isc/string.h> 37897be3a4Schristos #include <isc/time.h> 38897be3a4Schristos #include <isc/util.h> 39897be3a4Schristos 40897be3a4Schristos #define NS_PER_S 1000000000 /*%< Nanoseconds per second. */ 41897be3a4Schristos #define NS_PER_US 1000 /*%< Nanoseconds per microsecond. */ 42897be3a4Schristos #define US_PER_S 1000000 /*%< Microseconds per second. */ 43897be3a4Schristos 44897be3a4Schristos /* 45897be3a4Schristos * All of the INSIST()s checks of nanoseconds < NS_PER_S are for 46897be3a4Schristos * consistency checking of the type. In lieu of magic numbers, it 47897be3a4Schristos * is the best we've got. The check is only performed on functions which 48897be3a4Schristos * need an initialized type. 49897be3a4Schristos */ 50897be3a4Schristos 51897be3a4Schristos #ifndef ISC_FIX_TV_USEC 52897be3a4Schristos #define ISC_FIX_TV_USEC 1 53897be3a4Schristos #endif 54897be3a4Schristos 55897be3a4Schristos /*% 56897be3a4Schristos *** Intervals 57897be3a4Schristos ***/ 58897be3a4Schristos 59897be3a4Schristos static isc_interval_t zero_interval = { 0, 0 }; 60897be3a4Schristos isc_interval_t *isc_interval_zero = &zero_interval; 61897be3a4Schristos 62897be3a4Schristos #if ISC_FIX_TV_USEC 63897be3a4Schristos static inline void 64897be3a4Schristos fix_tv_usec(struct timeval *tv) { 65897be3a4Schristos isc_boolean_t fixed = ISC_FALSE; 66897be3a4Schristos 67897be3a4Schristos if (tv->tv_usec < 0) { 68897be3a4Schristos fixed = ISC_TRUE; 69897be3a4Schristos do { 70897be3a4Schristos tv->tv_sec -= 1; 71897be3a4Schristos tv->tv_usec += US_PER_S; 72897be3a4Schristos } while (tv->tv_usec < 0); 73897be3a4Schristos } else if (tv->tv_usec >= US_PER_S) { 74897be3a4Schristos fixed = ISC_TRUE; 75897be3a4Schristos do { 76897be3a4Schristos tv->tv_sec += 1; 77897be3a4Schristos tv->tv_usec -= US_PER_S; 78897be3a4Schristos } while (tv->tv_usec >=US_PER_S); 79897be3a4Schristos } 80897be3a4Schristos /* 81897be3a4Schristos * Call syslog directly as was are called from the logging functions. 82897be3a4Schristos */ 83897be3a4Schristos if (fixed) 84897be3a4Schristos (void)syslog(LOG_ERR, "gettimeofday returned bad tv_usec: corrected"); 85897be3a4Schristos } 86897be3a4Schristos #endif 87897be3a4Schristos 88897be3a4Schristos void 89897be3a4Schristos isc_interval_set(isc_interval_t *i, 90897be3a4Schristos unsigned int seconds, unsigned int nanoseconds) 91897be3a4Schristos { 92897be3a4Schristos REQUIRE(i != NULL); 93897be3a4Schristos REQUIRE(nanoseconds < NS_PER_S); 94897be3a4Schristos 95897be3a4Schristos i->seconds = seconds; 96897be3a4Schristos i->nanoseconds = nanoseconds; 97897be3a4Schristos } 98897be3a4Schristos 99897be3a4Schristos isc_boolean_t 100897be3a4Schristos isc_interval_iszero(const isc_interval_t *i) { 101897be3a4Schristos REQUIRE(i != NULL); 102897be3a4Schristos INSIST(i->nanoseconds < NS_PER_S); 103897be3a4Schristos 104897be3a4Schristos if (i->seconds == 0 && i->nanoseconds == 0) 105897be3a4Schristos return (ISC_TRUE); 106897be3a4Schristos 107897be3a4Schristos return (ISC_FALSE); 108897be3a4Schristos } 109897be3a4Schristos 110897be3a4Schristos 111897be3a4Schristos /*** 112897be3a4Schristos *** Absolute Times 113897be3a4Schristos ***/ 114897be3a4Schristos 115897be3a4Schristos static isc_time_t epoch = { 0, 0 }; 116897be3a4Schristos isc_time_t *isc_time_epoch = &epoch; 117897be3a4Schristos 118897be3a4Schristos void 119897be3a4Schristos isc_time_set(isc_time_t *t, unsigned int seconds, unsigned int nanoseconds) { 120897be3a4Schristos REQUIRE(t != NULL); 121897be3a4Schristos REQUIRE(nanoseconds < NS_PER_S); 122897be3a4Schristos 123897be3a4Schristos t->seconds = seconds; 124897be3a4Schristos t->nanoseconds = nanoseconds; 125897be3a4Schristos } 126897be3a4Schristos 127897be3a4Schristos void 128897be3a4Schristos isc_time_settoepoch(isc_time_t *t) { 129897be3a4Schristos REQUIRE(t != NULL); 130897be3a4Schristos 131897be3a4Schristos t->seconds = 0; 132897be3a4Schristos t->nanoseconds = 0; 133897be3a4Schristos } 134897be3a4Schristos 135897be3a4Schristos isc_boolean_t 136897be3a4Schristos isc_time_isepoch(const isc_time_t *t) { 137897be3a4Schristos REQUIRE(t != NULL); 138897be3a4Schristos INSIST(t->nanoseconds < NS_PER_S); 139897be3a4Schristos 140897be3a4Schristos if (t->seconds == 0 && t->nanoseconds == 0) 141897be3a4Schristos return (ISC_TRUE); 142897be3a4Schristos 143897be3a4Schristos return (ISC_FALSE); 144897be3a4Schristos } 145897be3a4Schristos 146897be3a4Schristos 147897be3a4Schristos isc_result_t 148897be3a4Schristos isc_time_now(isc_time_t *t) { 149897be3a4Schristos struct timeval tv; 150897be3a4Schristos char strbuf[ISC_STRERRORSIZE]; 151897be3a4Schristos 152897be3a4Schristos REQUIRE(t != NULL); 153897be3a4Schristos 154897be3a4Schristos if (gettimeofday(&tv, NULL) == -1) { 155897be3a4Schristos isc__strerror(errno, strbuf, sizeof(strbuf)); 156897be3a4Schristos UNEXPECTED_ERROR(__FILE__, __LINE__, "%s", strbuf); 157897be3a4Schristos return (ISC_R_UNEXPECTED); 158897be3a4Schristos } 159897be3a4Schristos 160897be3a4Schristos /* 161897be3a4Schristos * Does POSIX guarantee the signedness of tv_sec and tv_usec? If not, 162897be3a4Schristos * then this test will generate warnings for platforms on which it is 163897be3a4Schristos * unsigned. In any event, the chances of any of these problems 164897be3a4Schristos * happening are pretty much zero, but since the libisc library ensures 165897be3a4Schristos * certain things to be true ... 166897be3a4Schristos */ 167897be3a4Schristos #if ISC_FIX_TV_USEC 168897be3a4Schristos fix_tv_usec(&tv); 169897be3a4Schristos if (tv.tv_sec < 0) 170897be3a4Schristos return (ISC_R_UNEXPECTED); 171897be3a4Schristos #else 172897be3a4Schristos if (tv.tv_sec < 0 || tv.tv_usec < 0 || tv.tv_usec >= US_PER_S) 173897be3a4Schristos return (ISC_R_UNEXPECTED); 174897be3a4Schristos #endif 175897be3a4Schristos 176897be3a4Schristos /* 177897be3a4Schristos * Ensure the tv_sec value fits in t->seconds. 178897be3a4Schristos */ 179897be3a4Schristos if (sizeof(tv.tv_sec) > sizeof(t->seconds) && 180897be3a4Schristos ((tv.tv_sec | (unsigned int)-1) ^ (unsigned int)-1) != 0U) 181897be3a4Schristos return (ISC_R_RANGE); 182897be3a4Schristos 183897be3a4Schristos t->seconds = tv.tv_sec; 184897be3a4Schristos t->nanoseconds = tv.tv_usec * NS_PER_US; 185897be3a4Schristos 186897be3a4Schristos return (ISC_R_SUCCESS); 187897be3a4Schristos } 188897be3a4Schristos 189897be3a4Schristos isc_result_t 190897be3a4Schristos isc_time_nowplusinterval(isc_time_t *t, const isc_interval_t *i) { 191897be3a4Schristos struct timeval tv; 192897be3a4Schristos char strbuf[ISC_STRERRORSIZE]; 193897be3a4Schristos 194897be3a4Schristos REQUIRE(t != NULL); 195897be3a4Schristos REQUIRE(i != NULL); 196897be3a4Schristos INSIST(i->nanoseconds < NS_PER_S); 197897be3a4Schristos 198897be3a4Schristos if (gettimeofday(&tv, NULL) == -1) { 199897be3a4Schristos isc__strerror(errno, strbuf, sizeof(strbuf)); 200897be3a4Schristos UNEXPECTED_ERROR(__FILE__, __LINE__, "%s", strbuf); 201897be3a4Schristos return (ISC_R_UNEXPECTED); 202897be3a4Schristos } 203897be3a4Schristos 204897be3a4Schristos /* 205897be3a4Schristos * Does POSIX guarantee the signedness of tv_sec and tv_usec? If not, 206897be3a4Schristos * then this test will generate warnings for platforms on which it is 207897be3a4Schristos * unsigned. In any event, the chances of any of these problems 208897be3a4Schristos * happening are pretty much zero, but since the libisc library ensures 209897be3a4Schristos * certain things to be true ... 210897be3a4Schristos */ 211897be3a4Schristos #if ISC_FIX_TV_USEC 212897be3a4Schristos fix_tv_usec(&tv); 213897be3a4Schristos if (tv.tv_sec < 0) 214897be3a4Schristos return (ISC_R_UNEXPECTED); 215897be3a4Schristos #else 216897be3a4Schristos if (tv.tv_sec < 0 || tv.tv_usec < 0 || tv.tv_usec >= US_PER_S) 217897be3a4Schristos return (ISC_R_UNEXPECTED); 218897be3a4Schristos #endif 219897be3a4Schristos 220897be3a4Schristos /* 221897be3a4Schristos * Ensure the resulting seconds value fits in the size of an 222897be3a4Schristos * unsigned int. (It is written this way as a slight optimization; 223897be3a4Schristos * note that even if both values == INT_MAX, then when added 224897be3a4Schristos * and getting another 1 added below the result is UINT_MAX.) 225897be3a4Schristos */ 226897be3a4Schristos if ((tv.tv_sec > INT_MAX || i->seconds > INT_MAX) && 227897be3a4Schristos ((long long)tv.tv_sec + i->seconds > UINT_MAX)) 228897be3a4Schristos return (ISC_R_RANGE); 229897be3a4Schristos 230897be3a4Schristos t->seconds = tv.tv_sec + i->seconds; 231897be3a4Schristos t->nanoseconds = tv.tv_usec * NS_PER_US + i->nanoseconds; 232897be3a4Schristos if (t->nanoseconds >= NS_PER_S) { 233897be3a4Schristos t->seconds++; 234897be3a4Schristos t->nanoseconds -= NS_PER_S; 235897be3a4Schristos } 236897be3a4Schristos 237897be3a4Schristos return (ISC_R_SUCCESS); 238897be3a4Schristos } 239897be3a4Schristos 240897be3a4Schristos int 241897be3a4Schristos isc_time_compare(const isc_time_t *t1, const isc_time_t *t2) { 242897be3a4Schristos REQUIRE(t1 != NULL && t2 != NULL); 243897be3a4Schristos INSIST(t1->nanoseconds < NS_PER_S && t2->nanoseconds < NS_PER_S); 244897be3a4Schristos 245897be3a4Schristos if (t1->seconds < t2->seconds) 246897be3a4Schristos return (-1); 247897be3a4Schristos if (t1->seconds > t2->seconds) 248897be3a4Schristos return (1); 249897be3a4Schristos if (t1->nanoseconds < t2->nanoseconds) 250897be3a4Schristos return (-1); 251897be3a4Schristos if (t1->nanoseconds > t2->nanoseconds) 252897be3a4Schristos return (1); 253897be3a4Schristos return (0); 254897be3a4Schristos } 255897be3a4Schristos 256897be3a4Schristos isc_result_t 257897be3a4Schristos isc_time_add(const isc_time_t *t, const isc_interval_t *i, isc_time_t *result) 258897be3a4Schristos { 259897be3a4Schristos REQUIRE(t != NULL && i != NULL && result != NULL); 260897be3a4Schristos INSIST(t->nanoseconds < NS_PER_S && i->nanoseconds < NS_PER_S); 261897be3a4Schristos 262897be3a4Schristos /* 263897be3a4Schristos * Ensure the resulting seconds value fits in the size of an 264897be3a4Schristos * unsigned int. (It is written this way as a slight optimization; 265897be3a4Schristos * note that even if both values == INT_MAX, then when added 266897be3a4Schristos * and getting another 1 added below the result is UINT_MAX.) 267897be3a4Schristos */ 268897be3a4Schristos if ((t->seconds > INT_MAX || i->seconds > INT_MAX) && 269897be3a4Schristos ((long long)t->seconds + i->seconds > UINT_MAX)) 270897be3a4Schristos return (ISC_R_RANGE); 271897be3a4Schristos 272897be3a4Schristos result->seconds = t->seconds + i->seconds; 273897be3a4Schristos result->nanoseconds = t->nanoseconds + i->nanoseconds; 274897be3a4Schristos if (result->nanoseconds >= NS_PER_S) { 275897be3a4Schristos result->seconds++; 276897be3a4Schristos result->nanoseconds -= NS_PER_S; 277897be3a4Schristos } 278897be3a4Schristos 279897be3a4Schristos return (ISC_R_SUCCESS); 280897be3a4Schristos } 281897be3a4Schristos 282897be3a4Schristos isc_result_t 283897be3a4Schristos isc_time_subtract(const isc_time_t *t, const isc_interval_t *i, 284897be3a4Schristos isc_time_t *result) 285897be3a4Schristos { 286897be3a4Schristos REQUIRE(t != NULL && i != NULL && result != NULL); 287897be3a4Schristos INSIST(t->nanoseconds < NS_PER_S && i->nanoseconds < NS_PER_S); 288897be3a4Schristos 289897be3a4Schristos if ((unsigned int)t->seconds < i->seconds || 290897be3a4Schristos ((unsigned int)t->seconds == i->seconds && 291897be3a4Schristos t->nanoseconds < i->nanoseconds)) 292897be3a4Schristos return (ISC_R_RANGE); 293897be3a4Schristos 294897be3a4Schristos result->seconds = t->seconds - i->seconds; 295897be3a4Schristos if (t->nanoseconds >= i->nanoseconds) 296897be3a4Schristos result->nanoseconds = t->nanoseconds - i->nanoseconds; 297897be3a4Schristos else { 298897be3a4Schristos result->nanoseconds = NS_PER_S - i->nanoseconds + 299897be3a4Schristos t->nanoseconds; 300897be3a4Schristos result->seconds--; 301897be3a4Schristos } 302897be3a4Schristos 303897be3a4Schristos return (ISC_R_SUCCESS); 304897be3a4Schristos } 305897be3a4Schristos 306897be3a4Schristos isc_uint64_t 307897be3a4Schristos isc_time_microdiff(const isc_time_t *t1, const isc_time_t *t2) { 308897be3a4Schristos isc_uint64_t i1, i2, i3; 309897be3a4Schristos 310897be3a4Schristos REQUIRE(t1 != NULL && t2 != NULL); 311897be3a4Schristos INSIST(t1->nanoseconds < NS_PER_S && t2->nanoseconds < NS_PER_S); 312897be3a4Schristos 313897be3a4Schristos i1 = (isc_uint64_t)t1->seconds * NS_PER_S + t1->nanoseconds; 314897be3a4Schristos i2 = (isc_uint64_t)t2->seconds * NS_PER_S + t2->nanoseconds; 315897be3a4Schristos 316897be3a4Schristos if (i1 <= i2) 317897be3a4Schristos return (0); 318897be3a4Schristos 319897be3a4Schristos i3 = i1 - i2; 320897be3a4Schristos 321897be3a4Schristos /* 322897be3a4Schristos * Convert to microseconds. 323897be3a4Schristos */ 324897be3a4Schristos i3 /= NS_PER_US; 325897be3a4Schristos 326897be3a4Schristos return (i3); 327897be3a4Schristos } 328897be3a4Schristos 329897be3a4Schristos isc_uint32_t 330897be3a4Schristos isc_time_seconds(const isc_time_t *t) { 331897be3a4Schristos REQUIRE(t != NULL); 332897be3a4Schristos INSIST(t->nanoseconds < NS_PER_S); 333897be3a4Schristos 334897be3a4Schristos return ((isc_uint32_t)t->seconds); 335897be3a4Schristos } 336897be3a4Schristos 337897be3a4Schristos isc_result_t 338897be3a4Schristos isc_time_secondsastimet(const isc_time_t *t, time_t *secondsp) { 339897be3a4Schristos time_t seconds; 340897be3a4Schristos 341897be3a4Schristos REQUIRE(t != NULL); 342897be3a4Schristos INSIST(t->nanoseconds < NS_PER_S); 343897be3a4Schristos 344897be3a4Schristos /* 345897be3a4Schristos * Ensure that the number of seconds represented by t->seconds 346897be3a4Schristos * can be represented by a time_t. Since t->seconds is an unsigned 347897be3a4Schristos * int and since time_t is mostly opaque, this is trickier than 348897be3a4Schristos * it seems. (This standardized opaqueness of time_t is *very* 349897be3a4Schristos * frustrating; time_t is not even limited to being an integral 350897be3a4Schristos * type.) 351897be3a4Schristos * 352897be3a4Schristos * The mission, then, is to avoid generating any kind of warning 353897be3a4Schristos * about "signed versus unsigned" while trying to determine if the 354897be3a4Schristos * the unsigned int t->seconds is out range for tv_sec, which is 355897be3a4Schristos * pretty much only true if time_t is a signed integer of the same 356897be3a4Schristos * size as the return value of isc_time_seconds. 357897be3a4Schristos * 358897be3a4Schristos * If the paradox in the if clause below is true, t->seconds is out 359897be3a4Schristos * of range for time_t. 360897be3a4Schristos */ 361897be3a4Schristos seconds = (time_t)t->seconds; 362897be3a4Schristos 363897be3a4Schristos INSIST(sizeof(unsigned int) == sizeof(isc_uint32_t)); 364897be3a4Schristos INSIST(sizeof(time_t) >= sizeof(isc_uint32_t)); 365897be3a4Schristos 366897be3a4Schristos if (t->seconds > (~0U>>1) && seconds <= (time_t)(~0U>>1)) 367897be3a4Schristos return (ISC_R_RANGE); 368897be3a4Schristos 369897be3a4Schristos *secondsp = seconds; 370897be3a4Schristos 371897be3a4Schristos return (ISC_R_SUCCESS); 372897be3a4Schristos } 373897be3a4Schristos 374897be3a4Schristos isc_uint32_t 375897be3a4Schristos isc_time_nanoseconds(const isc_time_t *t) { 376897be3a4Schristos REQUIRE(t != NULL); 377897be3a4Schristos 378897be3a4Schristos ENSURE(t->nanoseconds < NS_PER_S); 379897be3a4Schristos 380897be3a4Schristos return ((isc_uint32_t)t->nanoseconds); 381897be3a4Schristos } 382897be3a4Schristos 383897be3a4Schristos void 384897be3a4Schristos isc_time_formattimestamp(const isc_time_t *t, char *buf, unsigned int len) { 385897be3a4Schristos time_t now; 386897be3a4Schristos unsigned int flen; 387897be3a4Schristos 388897be3a4Schristos REQUIRE(len > 0); 389897be3a4Schristos 390897be3a4Schristos now = (time_t) t->seconds; 391897be3a4Schristos flen = strftime(buf, len, "%d-%b-%Y %X", localtime(&now)); 392897be3a4Schristos INSIST(flen < len); 393897be3a4Schristos if (flen != 0) 394897be3a4Schristos snprintf(buf + flen, len - flen, 395897be3a4Schristos ".%03u", t->nanoseconds / 1000000); 396897be3a4Schristos else 397897be3a4Schristos snprintf(buf, len, "99-Bad-9999 99:99:99.999"); 398897be3a4Schristos } 399897be3a4Schristos 400897be3a4Schristos void 401897be3a4Schristos isc_time_formathttptimestamp(const isc_time_t *t, char *buf, unsigned int len) { 402897be3a4Schristos time_t now; 403897be3a4Schristos unsigned int flen; 404897be3a4Schristos 405897be3a4Schristos REQUIRE(len > 0); 406897be3a4Schristos 407897be3a4Schristos now = (time_t)t->seconds; 408897be3a4Schristos flen = strftime(buf, len, "%a, %d %b %Y %H:%M:%S GMT", gmtime(&now)); 409897be3a4Schristos INSIST(flen < len); 410897be3a4Schristos } 411897be3a4Schristos 412897be3a4Schristos void 413897be3a4Schristos isc_time_formatISO8601(const isc_time_t *t, char *buf, unsigned int len) { 414897be3a4Schristos time_t now; 415897be3a4Schristos unsigned int flen; 416897be3a4Schristos 417897be3a4Schristos REQUIRE(len > 0); 418897be3a4Schristos 419897be3a4Schristos now = (time_t)t->seconds; 420897be3a4Schristos flen = strftime(buf, len, "%Y-%m-%dT%H:%M:%SZ", gmtime(&now)); 421897be3a4Schristos INSIST(flen < len); 422897be3a4Schristos } 423