1*eabc0478Schristos /* $NetBSD: time.c,v 1.2 2024/08/18 20:47:16 christos Exp $ */ 2897be3a4Schristos 3897be3a4Schristos /* 4897be3a4Schristos * Copyright (C) 2004, 2006-2009 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: time.c,v 1.52 2009/08/14 07:51:08 marka Exp */ 21897be3a4Schristos 22897be3a4Schristos #include <config.h> 23897be3a4Schristos 24897be3a4Schristos #include <errno.h> 25897be3a4Schristos #include <limits.h> 26897be3a4Schristos #include <stddef.h> 27897be3a4Schristos #include <stdlib.h> 28897be3a4Schristos #include <string.h> 29897be3a4Schristos #include <time.h> 30897be3a4Schristos 31897be3a4Schristos #include <windows.h> 32897be3a4Schristos 33897be3a4Schristos #include <isc/assertions.h> 34897be3a4Schristos #include <isc/time.h> 35897be3a4Schristos #include <isc/util.h> 36897be3a4Schristos 37897be3a4Schristos /* 38897be3a4Schristos * struct FILETIME uses "100-nanoseconds intervals". 39897be3a4Schristos * NS / S = 1000000000 (10^9). 40897be3a4Schristos * While it is reasonably obvious that this makes the needed 41897be3a4Schristos * conversion factor 10^7, it is coded this way for additional clarity. 42897be3a4Schristos */ 43897be3a4Schristos #define NS_PER_S 1000000000 44897be3a4Schristos #define NS_INTERVAL 100 45897be3a4Schristos #define INTERVALS_PER_S (NS_PER_S / NS_INTERVAL) 46897be3a4Schristos #define UINT64_MAX _UI64_MAX 47897be3a4Schristos 48897be3a4Schristos /*** 49897be3a4Schristos *** Absolute Times 50897be3a4Schristos ***/ 51897be3a4Schristos 52897be3a4Schristos static isc_time_t epoch = { { 0, 0 } }; 53897be3a4Schristos LIBISC_EXTERNAL_DATA isc_time_t *isc_time_epoch = &epoch; 54897be3a4Schristos 55897be3a4Schristos /*** 56897be3a4Schristos *** Intervals 57897be3a4Schristos ***/ 58897be3a4Schristos 59897be3a4Schristos static isc_interval_t zero_interval = { 0 }; 60897be3a4Schristos LIBISC_EXTERNAL_DATA isc_interval_t *isc_interval_zero = &zero_interval; 61897be3a4Schristos 62897be3a4Schristos void 63897be3a4Schristos isc_interval_set(isc_interval_t *i, unsigned int seconds, 64897be3a4Schristos unsigned int nanoseconds) 65897be3a4Schristos { 66897be3a4Schristos REQUIRE(i != NULL); 67897be3a4Schristos REQUIRE(nanoseconds < NS_PER_S); 68897be3a4Schristos 69897be3a4Schristos /* 70897be3a4Schristos * This rounds nanoseconds up not down. 71897be3a4Schristos */ 72897be3a4Schristos i->interval = (LONGLONG)seconds * INTERVALS_PER_S 73897be3a4Schristos + (nanoseconds + NS_INTERVAL - 1) / NS_INTERVAL; 74897be3a4Schristos } 75897be3a4Schristos 76897be3a4Schristos isc_boolean_t 77897be3a4Schristos isc_interval_iszero(const isc_interval_t *i) { 78897be3a4Schristos REQUIRE(i != NULL); 79897be3a4Schristos if (i->interval == 0) 80897be3a4Schristos return (ISC_TRUE); 81897be3a4Schristos 82897be3a4Schristos return (ISC_FALSE); 83897be3a4Schristos } 84897be3a4Schristos 85897be3a4Schristos void 86897be3a4Schristos isc_time_set(isc_time_t *t, unsigned int seconds, unsigned int nanoseconds) { 87897be3a4Schristos SYSTEMTIME epoch = { 1970, 1, 4, 1, 0, 0, 0, 0 }; 88897be3a4Schristos FILETIME temp; 89897be3a4Schristos ULARGE_INTEGER i1; 90897be3a4Schristos 91897be3a4Schristos REQUIRE(t != NULL); 92897be3a4Schristos REQUIRE(nanoseconds < NS_PER_S); 93897be3a4Schristos 94897be3a4Schristos SystemTimeToFileTime(&epoch, &temp); 95897be3a4Schristos 96897be3a4Schristos i1.LowPart = t->absolute.dwLowDateTime; 97897be3a4Schristos i1.HighPart = t->absolute.dwHighDateTime; 98897be3a4Schristos 99897be3a4Schristos i1.QuadPart += (unsigned __int64)nanoseconds/100; 100897be3a4Schristos i1.QuadPart += (unsigned __int64)seconds*10000000; 101897be3a4Schristos 102897be3a4Schristos t->absolute.dwLowDateTime = i1.LowPart; 103897be3a4Schristos t->absolute.dwHighDateTime = i1.HighPart; 104897be3a4Schristos } 105897be3a4Schristos 106897be3a4Schristos void 107897be3a4Schristos isc_time_settoepoch(isc_time_t *t) { 108897be3a4Schristos REQUIRE(t != NULL); 109897be3a4Schristos 110897be3a4Schristos t->absolute.dwLowDateTime = 0; 111897be3a4Schristos t->absolute.dwHighDateTime = 0; 112897be3a4Schristos } 113897be3a4Schristos 114897be3a4Schristos isc_boolean_t 115897be3a4Schristos isc_time_isepoch(const isc_time_t *t) { 116897be3a4Schristos REQUIRE(t != NULL); 117897be3a4Schristos 118897be3a4Schristos if (t->absolute.dwLowDateTime == 0 && 119897be3a4Schristos t->absolute.dwHighDateTime == 0) 120897be3a4Schristos return (ISC_TRUE); 121897be3a4Schristos 122897be3a4Schristos return (ISC_FALSE); 123897be3a4Schristos } 124897be3a4Schristos 125897be3a4Schristos isc_result_t 126897be3a4Schristos isc_time_now(isc_time_t *t) { 127897be3a4Schristos REQUIRE(t != NULL); 128897be3a4Schristos 129897be3a4Schristos GetSystemTimeAsFileTime(&t->absolute); 130897be3a4Schristos 131897be3a4Schristos return (ISC_R_SUCCESS); 132897be3a4Schristos } 133897be3a4Schristos 134897be3a4Schristos isc_result_t 135897be3a4Schristos isc_time_nowplusinterval(isc_time_t *t, const isc_interval_t *i) { 136897be3a4Schristos ULARGE_INTEGER i1; 137897be3a4Schristos 138897be3a4Schristos REQUIRE(t != NULL); 139897be3a4Schristos REQUIRE(i != NULL); 140897be3a4Schristos 141897be3a4Schristos GetSystemTimeAsFileTime(&t->absolute); 142897be3a4Schristos 143897be3a4Schristos i1.LowPart = t->absolute.dwLowDateTime; 144897be3a4Schristos i1.HighPart = t->absolute.dwHighDateTime; 145897be3a4Schristos 146897be3a4Schristos if (UINT64_MAX - i1.QuadPart < (unsigned __int64)i->interval) 147897be3a4Schristos return (ISC_R_RANGE); 148897be3a4Schristos 149897be3a4Schristos i1.QuadPart += i->interval; 150897be3a4Schristos 151897be3a4Schristos t->absolute.dwLowDateTime = i1.LowPart; 152897be3a4Schristos t->absolute.dwHighDateTime = i1.HighPart; 153897be3a4Schristos 154897be3a4Schristos return (ISC_R_SUCCESS); 155897be3a4Schristos } 156897be3a4Schristos 157897be3a4Schristos int 158897be3a4Schristos isc_time_compare(const isc_time_t *t1, const isc_time_t *t2) { 159897be3a4Schristos REQUIRE(t1 != NULL && t2 != NULL); 160897be3a4Schristos 161897be3a4Schristos return ((int)CompareFileTime(&t1->absolute, &t2->absolute)); 162897be3a4Schristos } 163897be3a4Schristos 164897be3a4Schristos isc_result_t 165897be3a4Schristos isc_time_add(const isc_time_t *t, const isc_interval_t *i, isc_time_t *result) 166897be3a4Schristos { 167897be3a4Schristos ULARGE_INTEGER i1; 168897be3a4Schristos 169897be3a4Schristos REQUIRE(t != NULL && i != NULL && result != NULL); 170897be3a4Schristos 171897be3a4Schristos i1.LowPart = t->absolute.dwLowDateTime; 172897be3a4Schristos i1.HighPart = t->absolute.dwHighDateTime; 173897be3a4Schristos 174897be3a4Schristos if (UINT64_MAX - i1.QuadPart < (unsigned __int64)i->interval) 175897be3a4Schristos return (ISC_R_RANGE); 176897be3a4Schristos 177897be3a4Schristos i1.QuadPart += i->interval; 178897be3a4Schristos 179897be3a4Schristos result->absolute.dwLowDateTime = i1.LowPart; 180897be3a4Schristos result->absolute.dwHighDateTime = i1.HighPart; 181897be3a4Schristos 182897be3a4Schristos return (ISC_R_SUCCESS); 183897be3a4Schristos } 184897be3a4Schristos 185897be3a4Schristos isc_result_t 186897be3a4Schristos isc_time_subtract(const isc_time_t *t, const isc_interval_t *i, 187897be3a4Schristos isc_time_t *result) { 188897be3a4Schristos ULARGE_INTEGER i1; 189897be3a4Schristos 190897be3a4Schristos REQUIRE(t != NULL && i != NULL && result != NULL); 191897be3a4Schristos 192897be3a4Schristos i1.LowPart = t->absolute.dwLowDateTime; 193897be3a4Schristos i1.HighPart = t->absolute.dwHighDateTime; 194897be3a4Schristos 195897be3a4Schristos if (i1.QuadPart < (unsigned __int64) i->interval) 196897be3a4Schristos return (ISC_R_RANGE); 197897be3a4Schristos 198897be3a4Schristos i1.QuadPart -= i->interval; 199897be3a4Schristos 200897be3a4Schristos result->absolute.dwLowDateTime = i1.LowPart; 201897be3a4Schristos result->absolute.dwHighDateTime = i1.HighPart; 202897be3a4Schristos 203897be3a4Schristos return (ISC_R_SUCCESS); 204897be3a4Schristos } 205897be3a4Schristos 206897be3a4Schristos isc_uint64_t 207897be3a4Schristos isc_time_microdiff(const isc_time_t *t1, const isc_time_t *t2) { 208897be3a4Schristos ULARGE_INTEGER i1, i2; 209897be3a4Schristos LONGLONG i3; 210897be3a4Schristos 211897be3a4Schristos REQUIRE(t1 != NULL && t2 != NULL); 212897be3a4Schristos 213897be3a4Schristos i1.LowPart = t1->absolute.dwLowDateTime; 214897be3a4Schristos i1.HighPart = t1->absolute.dwHighDateTime; 215897be3a4Schristos i2.LowPart = t2->absolute.dwLowDateTime; 216897be3a4Schristos i2.HighPart = t2->absolute.dwHighDateTime; 217897be3a4Schristos 218897be3a4Schristos if (i1.QuadPart <= i2.QuadPart) 219897be3a4Schristos return (0); 220897be3a4Schristos 221897be3a4Schristos /* 222897be3a4Schristos * Convert to microseconds. 223897be3a4Schristos */ 224897be3a4Schristos i3 = (i1.QuadPart - i2.QuadPart) / 10; 225897be3a4Schristos 226897be3a4Schristos return (i3); 227897be3a4Schristos } 228897be3a4Schristos 229897be3a4Schristos isc_uint32_t 230897be3a4Schristos isc_time_seconds(const isc_time_t *t) { 231897be3a4Schristos SYSTEMTIME epoch = { 1970, 1, 4, 1, 0, 0, 0, 0 }; 232897be3a4Schristos FILETIME temp; 233897be3a4Schristos ULARGE_INTEGER i1, i2; 234897be3a4Schristos LONGLONG i3; 235897be3a4Schristos 236897be3a4Schristos SystemTimeToFileTime(&epoch, &temp); 237897be3a4Schristos 238897be3a4Schristos i1.LowPart = t->absolute.dwLowDateTime; 239897be3a4Schristos i1.HighPart = t->absolute.dwHighDateTime; 240897be3a4Schristos i2.LowPart = temp.dwLowDateTime; 241897be3a4Schristos i2.HighPart = temp.dwHighDateTime; 242897be3a4Schristos 243897be3a4Schristos i3 = (i1.QuadPart - i2.QuadPart) / 10000000; 244897be3a4Schristos 245897be3a4Schristos return ((isc_uint32_t)i3); 246897be3a4Schristos } 247897be3a4Schristos 248897be3a4Schristos isc_uint32_t 249897be3a4Schristos isc_time_nanoseconds(const isc_time_t *t) { 250897be3a4Schristos ULARGE_INTEGER i; 251897be3a4Schristos 252897be3a4Schristos i.LowPart = t->absolute.dwLowDateTime; 253897be3a4Schristos i.HighPart = t->absolute.dwHighDateTime; 254897be3a4Schristos return ((isc_uint32_t)(i.QuadPart % 10000000) * 100); 255897be3a4Schristos } 256897be3a4Schristos 257897be3a4Schristos void 258897be3a4Schristos isc_time_formattimestamp(const isc_time_t *t, char *buf, unsigned int len) { 259897be3a4Schristos FILETIME localft; 260897be3a4Schristos SYSTEMTIME st; 261897be3a4Schristos char DateBuf[50]; 262897be3a4Schristos char TimeBuf[50]; 263897be3a4Schristos 264897be3a4Schristos static const char badtime[] = "99-Bad-9999 99:99:99.999"; 265897be3a4Schristos 266897be3a4Schristos REQUIRE(len > 0); 267897be3a4Schristos if (FileTimeToLocalFileTime(&t->absolute, &localft) && 268897be3a4Schristos FileTimeToSystemTime(&localft, &st)) { 269897be3a4Schristos GetDateFormat(LOCALE_USER_DEFAULT, 0, &st, "dd-MMM-yyyy", 270897be3a4Schristos DateBuf, 50); 271897be3a4Schristos GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOTIMEMARKER| 272897be3a4Schristos TIME_FORCE24HOURFORMAT, &st, NULL, TimeBuf, 50); 273897be3a4Schristos 274897be3a4Schristos snprintf(buf, len, "%s %s.%03u", DateBuf, TimeBuf, 275897be3a4Schristos st.wMilliseconds); 276897be3a4Schristos 277897be3a4Schristos } else 278897be3a4Schristos snprintf(buf, len, badtime); 279897be3a4Schristos } 280897be3a4Schristos 281897be3a4Schristos void 282897be3a4Schristos isc_time_formathttptimestamp(const isc_time_t *t, char *buf, unsigned int len) { 283897be3a4Schristos SYSTEMTIME st; 284897be3a4Schristos char DateBuf[50]; 285897be3a4Schristos char TimeBuf[50]; 286897be3a4Schristos 287897be3a4Schristos /* strftime() format: "%a, %d %b %Y %H:%M:%S GMT" */ 288897be3a4Schristos 289897be3a4Schristos REQUIRE(len > 0); 290897be3a4Schristos if (FileTimeToSystemTime(&t->absolute, &st)) { 291897be3a4Schristos GetDateFormat(LOCALE_USER_DEFAULT, 0, &st, 292897be3a4Schristos "ddd',', dd-MMM-yyyy", DateBuf, 50); 293897be3a4Schristos GetTimeFormat(LOCALE_USER_DEFAULT, 294897be3a4Schristos TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT, 295897be3a4Schristos &st, "hh':'mm':'ss", TimeBuf, 50); 296897be3a4Schristos 297897be3a4Schristos snprintf(buf, len, "%s %s GMT", DateBuf, TimeBuf); 298897be3a4Schristos } else { 299897be3a4Schristos buf[0] = 0; 300897be3a4Schristos } 301897be3a4Schristos } 302897be3a4Schristos 303897be3a4Schristos void 304897be3a4Schristos isc_time_formatISO8601(const isc_time_t *t, char *buf, unsigned int len) { 305897be3a4Schristos SYSTEMTIME st; 306897be3a4Schristos char DateBuf[50]; 307897be3a4Schristos char TimeBuf[50]; 308897be3a4Schristos 309897be3a4Schristos /* strtime() format: "%Y-%m-%dT%H:%M:%SZ" */ 310897be3a4Schristos 311897be3a4Schristos REQUIRE(len > 0); 312897be3a4Schristos if (FileTimeToSystemTime(&t->absolute, &st)) { 313897be3a4Schristos GetDateFormat(LOCALE_NEUTRAL, 0, &st, "yyyy-MM-dd", 314897be3a4Schristos DateBuf, 50); 315897be3a4Schristos GetTimeFormat(LOCALE_NEUTRAL, 316897be3a4Schristos TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT, 317897be3a4Schristos &st, "hh':'mm':'ss", TimeBuf, 50); 318897be3a4Schristos snprintf(buf, len, "%s%sZ", DateBuf, TimeBuf); 319897be3a4Schristos } else { 320897be3a4Schristos buf[0] = 0; 321897be3a4Schristos } 322897be3a4Schristos } 323