1/* $NetBSD: time.c,v 1.2 2024/08/18 20:47:16 christos Exp $ */ 2 3/* 4 * Copyright (C) 2004, 2006-2009 Internet Systems Consortium, Inc. ("ISC") 5 * Copyright (C) 1998-2001, 2003 Internet Software Consortium. 6 * 7 * Permission to use, copy, modify, and/or distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17 * PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20/* Id: time.c,v 1.52 2009/08/14 07:51:08 marka Exp */ 21 22#include <config.h> 23 24#include <errno.h> 25#include <limits.h> 26#include <stddef.h> 27#include <stdlib.h> 28#include <string.h> 29#include <time.h> 30 31#include <windows.h> 32 33#include <isc/assertions.h> 34#include <isc/time.h> 35#include <isc/util.h> 36 37/* 38 * struct FILETIME uses "100-nanoseconds intervals". 39 * NS / S = 1000000000 (10^9). 40 * While it is reasonably obvious that this makes the needed 41 * conversion factor 10^7, it is coded this way for additional clarity. 42 */ 43#define NS_PER_S 1000000000 44#define NS_INTERVAL 100 45#define INTERVALS_PER_S (NS_PER_S / NS_INTERVAL) 46#define UINT64_MAX _UI64_MAX 47 48/*** 49 *** Absolute Times 50 ***/ 51 52static isc_time_t epoch = { { 0, 0 } }; 53LIBISC_EXTERNAL_DATA isc_time_t *isc_time_epoch = &epoch; 54 55/*** 56 *** Intervals 57 ***/ 58 59static isc_interval_t zero_interval = { 0 }; 60LIBISC_EXTERNAL_DATA isc_interval_t *isc_interval_zero = &zero_interval; 61 62void 63isc_interval_set(isc_interval_t *i, unsigned int seconds, 64 unsigned int nanoseconds) 65{ 66 REQUIRE(i != NULL); 67 REQUIRE(nanoseconds < NS_PER_S); 68 69 /* 70 * This rounds nanoseconds up not down. 71 */ 72 i->interval = (LONGLONG)seconds * INTERVALS_PER_S 73 + (nanoseconds + NS_INTERVAL - 1) / NS_INTERVAL; 74} 75 76isc_boolean_t 77isc_interval_iszero(const isc_interval_t *i) { 78 REQUIRE(i != NULL); 79 if (i->interval == 0) 80 return (ISC_TRUE); 81 82 return (ISC_FALSE); 83} 84 85void 86isc_time_set(isc_time_t *t, unsigned int seconds, unsigned int nanoseconds) { 87 SYSTEMTIME epoch = { 1970, 1, 4, 1, 0, 0, 0, 0 }; 88 FILETIME temp; 89 ULARGE_INTEGER i1; 90 91 REQUIRE(t != NULL); 92 REQUIRE(nanoseconds < NS_PER_S); 93 94 SystemTimeToFileTime(&epoch, &temp); 95 96 i1.LowPart = t->absolute.dwLowDateTime; 97 i1.HighPart = t->absolute.dwHighDateTime; 98 99 i1.QuadPart += (unsigned __int64)nanoseconds/100; 100 i1.QuadPart += (unsigned __int64)seconds*10000000; 101 102 t->absolute.dwLowDateTime = i1.LowPart; 103 t->absolute.dwHighDateTime = i1.HighPart; 104} 105 106void 107isc_time_settoepoch(isc_time_t *t) { 108 REQUIRE(t != NULL); 109 110 t->absolute.dwLowDateTime = 0; 111 t->absolute.dwHighDateTime = 0; 112} 113 114isc_boolean_t 115isc_time_isepoch(const isc_time_t *t) { 116 REQUIRE(t != NULL); 117 118 if (t->absolute.dwLowDateTime == 0 && 119 t->absolute.dwHighDateTime == 0) 120 return (ISC_TRUE); 121 122 return (ISC_FALSE); 123} 124 125isc_result_t 126isc_time_now(isc_time_t *t) { 127 REQUIRE(t != NULL); 128 129 GetSystemTimeAsFileTime(&t->absolute); 130 131 return (ISC_R_SUCCESS); 132} 133 134isc_result_t 135isc_time_nowplusinterval(isc_time_t *t, const isc_interval_t *i) { 136 ULARGE_INTEGER i1; 137 138 REQUIRE(t != NULL); 139 REQUIRE(i != NULL); 140 141 GetSystemTimeAsFileTime(&t->absolute); 142 143 i1.LowPart = t->absolute.dwLowDateTime; 144 i1.HighPart = t->absolute.dwHighDateTime; 145 146 if (UINT64_MAX - i1.QuadPart < (unsigned __int64)i->interval) 147 return (ISC_R_RANGE); 148 149 i1.QuadPart += i->interval; 150 151 t->absolute.dwLowDateTime = i1.LowPart; 152 t->absolute.dwHighDateTime = i1.HighPart; 153 154 return (ISC_R_SUCCESS); 155} 156 157int 158isc_time_compare(const isc_time_t *t1, const isc_time_t *t2) { 159 REQUIRE(t1 != NULL && t2 != NULL); 160 161 return ((int)CompareFileTime(&t1->absolute, &t2->absolute)); 162} 163 164isc_result_t 165isc_time_add(const isc_time_t *t, const isc_interval_t *i, isc_time_t *result) 166{ 167 ULARGE_INTEGER i1; 168 169 REQUIRE(t != NULL && i != NULL && result != NULL); 170 171 i1.LowPart = t->absolute.dwLowDateTime; 172 i1.HighPart = t->absolute.dwHighDateTime; 173 174 if (UINT64_MAX - i1.QuadPart < (unsigned __int64)i->interval) 175 return (ISC_R_RANGE); 176 177 i1.QuadPart += i->interval; 178 179 result->absolute.dwLowDateTime = i1.LowPart; 180 result->absolute.dwHighDateTime = i1.HighPart; 181 182 return (ISC_R_SUCCESS); 183} 184 185isc_result_t 186isc_time_subtract(const isc_time_t *t, const isc_interval_t *i, 187 isc_time_t *result) { 188 ULARGE_INTEGER i1; 189 190 REQUIRE(t != NULL && i != NULL && result != NULL); 191 192 i1.LowPart = t->absolute.dwLowDateTime; 193 i1.HighPart = t->absolute.dwHighDateTime; 194 195 if (i1.QuadPart < (unsigned __int64) i->interval) 196 return (ISC_R_RANGE); 197 198 i1.QuadPart -= i->interval; 199 200 result->absolute.dwLowDateTime = i1.LowPart; 201 result->absolute.dwHighDateTime = i1.HighPart; 202 203 return (ISC_R_SUCCESS); 204} 205 206isc_uint64_t 207isc_time_microdiff(const isc_time_t *t1, const isc_time_t *t2) { 208 ULARGE_INTEGER i1, i2; 209 LONGLONG i3; 210 211 REQUIRE(t1 != NULL && t2 != NULL); 212 213 i1.LowPart = t1->absolute.dwLowDateTime; 214 i1.HighPart = t1->absolute.dwHighDateTime; 215 i2.LowPart = t2->absolute.dwLowDateTime; 216 i2.HighPart = t2->absolute.dwHighDateTime; 217 218 if (i1.QuadPart <= i2.QuadPart) 219 return (0); 220 221 /* 222 * Convert to microseconds. 223 */ 224 i3 = (i1.QuadPart - i2.QuadPart) / 10; 225 226 return (i3); 227} 228 229isc_uint32_t 230isc_time_seconds(const isc_time_t *t) { 231 SYSTEMTIME epoch = { 1970, 1, 4, 1, 0, 0, 0, 0 }; 232 FILETIME temp; 233 ULARGE_INTEGER i1, i2; 234 LONGLONG i3; 235 236 SystemTimeToFileTime(&epoch, &temp); 237 238 i1.LowPart = t->absolute.dwLowDateTime; 239 i1.HighPart = t->absolute.dwHighDateTime; 240 i2.LowPart = temp.dwLowDateTime; 241 i2.HighPart = temp.dwHighDateTime; 242 243 i3 = (i1.QuadPart - i2.QuadPart) / 10000000; 244 245 return ((isc_uint32_t)i3); 246} 247 248isc_uint32_t 249isc_time_nanoseconds(const isc_time_t *t) { 250 ULARGE_INTEGER i; 251 252 i.LowPart = t->absolute.dwLowDateTime; 253 i.HighPart = t->absolute.dwHighDateTime; 254 return ((isc_uint32_t)(i.QuadPart % 10000000) * 100); 255} 256 257void 258isc_time_formattimestamp(const isc_time_t *t, char *buf, unsigned int len) { 259 FILETIME localft; 260 SYSTEMTIME st; 261 char DateBuf[50]; 262 char TimeBuf[50]; 263 264 static const char badtime[] = "99-Bad-9999 99:99:99.999"; 265 266 REQUIRE(len > 0); 267 if (FileTimeToLocalFileTime(&t->absolute, &localft) && 268 FileTimeToSystemTime(&localft, &st)) { 269 GetDateFormat(LOCALE_USER_DEFAULT, 0, &st, "dd-MMM-yyyy", 270 DateBuf, 50); 271 GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOTIMEMARKER| 272 TIME_FORCE24HOURFORMAT, &st, NULL, TimeBuf, 50); 273 274 snprintf(buf, len, "%s %s.%03u", DateBuf, TimeBuf, 275 st.wMilliseconds); 276 277 } else 278 snprintf(buf, len, badtime); 279} 280 281void 282isc_time_formathttptimestamp(const isc_time_t *t, char *buf, unsigned int len) { 283 SYSTEMTIME st; 284 char DateBuf[50]; 285 char TimeBuf[50]; 286 287/* strftime() format: "%a, %d %b %Y %H:%M:%S GMT" */ 288 289 REQUIRE(len > 0); 290 if (FileTimeToSystemTime(&t->absolute, &st)) { 291 GetDateFormat(LOCALE_USER_DEFAULT, 0, &st, 292 "ddd',', dd-MMM-yyyy", DateBuf, 50); 293 GetTimeFormat(LOCALE_USER_DEFAULT, 294 TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT, 295 &st, "hh':'mm':'ss", TimeBuf, 50); 296 297 snprintf(buf, len, "%s %s GMT", DateBuf, TimeBuf); 298 } else { 299 buf[0] = 0; 300 } 301} 302 303void 304isc_time_formatISO8601(const isc_time_t *t, char *buf, unsigned int len) { 305 SYSTEMTIME st; 306 char DateBuf[50]; 307 char TimeBuf[50]; 308 309/* strtime() format: "%Y-%m-%dT%H:%M:%SZ" */ 310 311 REQUIRE(len > 0); 312 if (FileTimeToSystemTime(&t->absolute, &st)) { 313 GetDateFormat(LOCALE_NEUTRAL, 0, &st, "yyyy-MM-dd", 314 DateBuf, 50); 315 GetTimeFormat(LOCALE_NEUTRAL, 316 TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT, 317 &st, "hh':'mm':'ss", TimeBuf, 50); 318 snprintf(buf, len, "%s%sZ", DateBuf, TimeBuf); 319 } else { 320 buf[0] = 0; 321 } 322} 323