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