1290001Sglebius/* 2290001Sglebius * Copyright (C) 2004, 2006-2009 Internet Systems Consortium, Inc. ("ISC") 3290001Sglebius * Copyright (C) 1998-2001, 2003 Internet Software Consortium. 4290001Sglebius * 5290001Sglebius * Permission to use, copy, modify, and/or distribute this software for any 6290001Sglebius * purpose with or without fee is hereby granted, provided that the above 7290001Sglebius * copyright notice and this permission notice appear in all copies. 8290001Sglebius * 9290001Sglebius * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10290001Sglebius * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11290001Sglebius * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12290001Sglebius * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13290001Sglebius * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14290001Sglebius * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15290001Sglebius * PERFORMANCE OF THIS SOFTWARE. 16290001Sglebius */ 17290001Sglebius 18290001Sglebius/* $Id: time.c,v 1.52 2009/08/14 07:51:08 marka Exp $ */ 19290001Sglebius 20290001Sglebius#include <config.h> 21290001Sglebius 22290001Sglebius#include <errno.h> 23290001Sglebius#include <limits.h> 24290001Sglebius#include <stddef.h> 25290001Sglebius#include <stdlib.h> 26290001Sglebius#include <string.h> 27290001Sglebius#include <time.h> 28290001Sglebius 29290001Sglebius#include <windows.h> 30290001Sglebius 31290001Sglebius#include <isc/assertions.h> 32290001Sglebius#include <isc/time.h> 33290001Sglebius#include <isc/util.h> 34290001Sglebius 35290001Sglebius/* 36290001Sglebius * struct FILETIME uses "100-nanoseconds intervals". 37290001Sglebius * NS / S = 1000000000 (10^9). 38290001Sglebius * While it is reasonably obvious that this makes the needed 39290001Sglebius * conversion factor 10^7, it is coded this way for additional clarity. 40290001Sglebius */ 41290001Sglebius#define NS_PER_S 1000000000 42290001Sglebius#define NS_INTERVAL 100 43290001Sglebius#define INTERVALS_PER_S (NS_PER_S / NS_INTERVAL) 44290001Sglebius#define UINT64_MAX _UI64_MAX 45290001Sglebius 46290001Sglebius/*** 47290001Sglebius *** Absolute Times 48290001Sglebius ***/ 49290001Sglebius 50290001Sglebiusstatic isc_time_t epoch = { { 0, 0 } }; 51290001SglebiusLIBISC_EXTERNAL_DATA isc_time_t *isc_time_epoch = &epoch; 52290001Sglebius 53290001Sglebius/*** 54290001Sglebius *** Intervals 55290001Sglebius ***/ 56290001Sglebius 57290001Sglebiusstatic isc_interval_t zero_interval = { 0 }; 58290001SglebiusLIBISC_EXTERNAL_DATA isc_interval_t *isc_interval_zero = &zero_interval; 59290001Sglebius 60290001Sglebiusvoid 61290001Sglebiusisc_interval_set(isc_interval_t *i, unsigned int seconds, 62290001Sglebius unsigned int nanoseconds) 63290001Sglebius{ 64290001Sglebius REQUIRE(i != NULL); 65290001Sglebius REQUIRE(nanoseconds < NS_PER_S); 66290001Sglebius 67290001Sglebius /* 68290001Sglebius * This rounds nanoseconds up not down. 69290001Sglebius */ 70290001Sglebius i->interval = (LONGLONG)seconds * INTERVALS_PER_S 71290001Sglebius + (nanoseconds + NS_INTERVAL - 1) / NS_INTERVAL; 72290001Sglebius} 73290001Sglebius 74290001Sglebiusisc_boolean_t 75290001Sglebiusisc_interval_iszero(const isc_interval_t *i) { 76290001Sglebius REQUIRE(i != NULL); 77290001Sglebius if (i->interval == 0) 78290001Sglebius return (ISC_TRUE); 79290001Sglebius 80290001Sglebius return (ISC_FALSE); 81290001Sglebius} 82290001Sglebius 83290001Sglebiusvoid 84290001Sglebiusisc_time_set(isc_time_t *t, unsigned int seconds, unsigned int nanoseconds) { 85290001Sglebius SYSTEMTIME epoch = { 1970, 1, 4, 1, 0, 0, 0, 0 }; 86290001Sglebius FILETIME temp; 87290001Sglebius ULARGE_INTEGER i1; 88290001Sglebius 89290001Sglebius REQUIRE(t != NULL); 90290001Sglebius REQUIRE(nanoseconds < NS_PER_S); 91290001Sglebius 92290001Sglebius SystemTimeToFileTime(&epoch, &temp); 93290001Sglebius 94290001Sglebius i1.LowPart = t->absolute.dwLowDateTime; 95290001Sglebius i1.HighPart = t->absolute.dwHighDateTime; 96290001Sglebius 97290001Sglebius i1.QuadPart += (unsigned __int64)nanoseconds/100; 98290001Sglebius i1.QuadPart += (unsigned __int64)seconds*10000000; 99290001Sglebius 100290001Sglebius t->absolute.dwLowDateTime = i1.LowPart; 101290001Sglebius t->absolute.dwHighDateTime = i1.HighPart; 102290001Sglebius} 103290001Sglebius 104290001Sglebiusvoid 105290001Sglebiusisc_time_settoepoch(isc_time_t *t) { 106290001Sglebius REQUIRE(t != NULL); 107290001Sglebius 108290001Sglebius t->absolute.dwLowDateTime = 0; 109290001Sglebius t->absolute.dwHighDateTime = 0; 110290001Sglebius} 111290001Sglebius 112290001Sglebiusisc_boolean_t 113290001Sglebiusisc_time_isepoch(const isc_time_t *t) { 114290001Sglebius REQUIRE(t != NULL); 115290001Sglebius 116290001Sglebius if (t->absolute.dwLowDateTime == 0 && 117290001Sglebius t->absolute.dwHighDateTime == 0) 118290001Sglebius return (ISC_TRUE); 119290001Sglebius 120290001Sglebius return (ISC_FALSE); 121290001Sglebius} 122290001Sglebius 123290001Sglebiusisc_result_t 124290001Sglebiusisc_time_now(isc_time_t *t) { 125290001Sglebius REQUIRE(t != NULL); 126290001Sglebius 127290001Sglebius GetSystemTimeAsFileTime(&t->absolute); 128290001Sglebius 129290001Sglebius return (ISC_R_SUCCESS); 130290001Sglebius} 131290001Sglebius 132290001Sglebiusisc_result_t 133290001Sglebiusisc_time_nowplusinterval(isc_time_t *t, const isc_interval_t *i) { 134290001Sglebius ULARGE_INTEGER i1; 135290001Sglebius 136290001Sglebius REQUIRE(t != NULL); 137290001Sglebius REQUIRE(i != NULL); 138290001Sglebius 139290001Sglebius GetSystemTimeAsFileTime(&t->absolute); 140290001Sglebius 141290001Sglebius i1.LowPart = t->absolute.dwLowDateTime; 142290001Sglebius i1.HighPart = t->absolute.dwHighDateTime; 143290001Sglebius 144290001Sglebius if (UINT64_MAX - i1.QuadPart < (unsigned __int64)i->interval) 145290001Sglebius return (ISC_R_RANGE); 146290001Sglebius 147290001Sglebius i1.QuadPart += i->interval; 148290001Sglebius 149290001Sglebius t->absolute.dwLowDateTime = i1.LowPart; 150290001Sglebius t->absolute.dwHighDateTime = i1.HighPart; 151290001Sglebius 152290001Sglebius return (ISC_R_SUCCESS); 153290001Sglebius} 154290001Sglebius 155290001Sglebiusint 156290001Sglebiusisc_time_compare(const isc_time_t *t1, const isc_time_t *t2) { 157290001Sglebius REQUIRE(t1 != NULL && t2 != NULL); 158290001Sglebius 159290001Sglebius return ((int)CompareFileTime(&t1->absolute, &t2->absolute)); 160290001Sglebius} 161290001Sglebius 162290001Sglebiusisc_result_t 163290001Sglebiusisc_time_add(const isc_time_t *t, const isc_interval_t *i, isc_time_t *result) 164290001Sglebius{ 165290001Sglebius ULARGE_INTEGER i1; 166290001Sglebius 167290001Sglebius REQUIRE(t != NULL && i != NULL && result != NULL); 168290001Sglebius 169290001Sglebius i1.LowPart = t->absolute.dwLowDateTime; 170290001Sglebius i1.HighPart = t->absolute.dwHighDateTime; 171290001Sglebius 172290001Sglebius if (UINT64_MAX - i1.QuadPart < (unsigned __int64)i->interval) 173290001Sglebius return (ISC_R_RANGE); 174290001Sglebius 175290001Sglebius i1.QuadPart += i->interval; 176290001Sglebius 177290001Sglebius result->absolute.dwLowDateTime = i1.LowPart; 178290001Sglebius result->absolute.dwHighDateTime = i1.HighPart; 179290001Sglebius 180290001Sglebius return (ISC_R_SUCCESS); 181290001Sglebius} 182290001Sglebius 183290001Sglebiusisc_result_t 184290001Sglebiusisc_time_subtract(const isc_time_t *t, const isc_interval_t *i, 185290001Sglebius isc_time_t *result) { 186290001Sglebius ULARGE_INTEGER i1; 187290001Sglebius 188290001Sglebius REQUIRE(t != NULL && i != NULL && result != NULL); 189290001Sglebius 190290001Sglebius i1.LowPart = t->absolute.dwLowDateTime; 191290001Sglebius i1.HighPart = t->absolute.dwHighDateTime; 192290001Sglebius 193290001Sglebius if (i1.QuadPart < (unsigned __int64) i->interval) 194290001Sglebius return (ISC_R_RANGE); 195290001Sglebius 196290001Sglebius i1.QuadPart -= i->interval; 197290001Sglebius 198290001Sglebius result->absolute.dwLowDateTime = i1.LowPart; 199290001Sglebius result->absolute.dwHighDateTime = i1.HighPart; 200290001Sglebius 201290001Sglebius return (ISC_R_SUCCESS); 202290001Sglebius} 203290001Sglebius 204290001Sglebiusisc_uint64_t 205290001Sglebiusisc_time_microdiff(const isc_time_t *t1, const isc_time_t *t2) { 206290001Sglebius ULARGE_INTEGER i1, i2; 207290001Sglebius LONGLONG i3; 208290001Sglebius 209290001Sglebius REQUIRE(t1 != NULL && t2 != NULL); 210290001Sglebius 211290001Sglebius i1.LowPart = t1->absolute.dwLowDateTime; 212290001Sglebius i1.HighPart = t1->absolute.dwHighDateTime; 213290001Sglebius i2.LowPart = t2->absolute.dwLowDateTime; 214290001Sglebius i2.HighPart = t2->absolute.dwHighDateTime; 215290001Sglebius 216290001Sglebius if (i1.QuadPart <= i2.QuadPart) 217290001Sglebius return (0); 218290001Sglebius 219290001Sglebius /* 220290001Sglebius * Convert to microseconds. 221290001Sglebius */ 222290001Sglebius i3 = (i1.QuadPart - i2.QuadPart) / 10; 223290001Sglebius 224290001Sglebius return (i3); 225290001Sglebius} 226290001Sglebius 227290001Sglebiusisc_uint32_t 228290001Sglebiusisc_time_seconds(const isc_time_t *t) { 229290001Sglebius SYSTEMTIME epoch = { 1970, 1, 4, 1, 0, 0, 0, 0 }; 230290001Sglebius FILETIME temp; 231290001Sglebius ULARGE_INTEGER i1, i2; 232290001Sglebius LONGLONG i3; 233290001Sglebius 234290001Sglebius SystemTimeToFileTime(&epoch, &temp); 235290001Sglebius 236290001Sglebius i1.LowPart = t->absolute.dwLowDateTime; 237290001Sglebius i1.HighPart = t->absolute.dwHighDateTime; 238290001Sglebius i2.LowPart = temp.dwLowDateTime; 239290001Sglebius i2.HighPart = temp.dwHighDateTime; 240290001Sglebius 241290001Sglebius i3 = (i1.QuadPart - i2.QuadPart) / 10000000; 242290001Sglebius 243290001Sglebius return ((isc_uint32_t)i3); 244290001Sglebius} 245290001Sglebius 246290001Sglebiusisc_uint32_t 247290001Sglebiusisc_time_nanoseconds(const isc_time_t *t) { 248290001Sglebius ULARGE_INTEGER i; 249290001Sglebius 250290001Sglebius i.LowPart = t->absolute.dwLowDateTime; 251290001Sglebius i.HighPart = t->absolute.dwHighDateTime; 252290001Sglebius return ((isc_uint32_t)(i.QuadPart % 10000000) * 100); 253290001Sglebius} 254290001Sglebius 255290001Sglebiusvoid 256290001Sglebiusisc_time_formattimestamp(const isc_time_t *t, char *buf, unsigned int len) { 257290001Sglebius FILETIME localft; 258290001Sglebius SYSTEMTIME st; 259290001Sglebius char DateBuf[50]; 260290001Sglebius char TimeBuf[50]; 261290001Sglebius 262290001Sglebius static const char badtime[] = "99-Bad-9999 99:99:99.999"; 263290001Sglebius 264290001Sglebius REQUIRE(len > 0); 265290001Sglebius if (FileTimeToLocalFileTime(&t->absolute, &localft) && 266290001Sglebius FileTimeToSystemTime(&localft, &st)) { 267290001Sglebius GetDateFormat(LOCALE_USER_DEFAULT, 0, &st, "dd-MMM-yyyy", 268290001Sglebius DateBuf, 50); 269290001Sglebius GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOTIMEMARKER| 270290001Sglebius TIME_FORCE24HOURFORMAT, &st, NULL, TimeBuf, 50); 271290001Sglebius 272290001Sglebius snprintf(buf, len, "%s %s.%03u", DateBuf, TimeBuf, 273290001Sglebius st.wMilliseconds); 274290001Sglebius 275290001Sglebius } else 276290001Sglebius snprintf(buf, len, badtime); 277290001Sglebius} 278290001Sglebius 279290001Sglebiusvoid 280290001Sglebiusisc_time_formathttptimestamp(const isc_time_t *t, char *buf, unsigned int len) { 281290001Sglebius SYSTEMTIME st; 282290001Sglebius char DateBuf[50]; 283290001Sglebius char TimeBuf[50]; 284290001Sglebius 285290001Sglebius/* strftime() format: "%a, %d %b %Y %H:%M:%S GMT" */ 286290001Sglebius 287290001Sglebius REQUIRE(len > 0); 288290001Sglebius if (FileTimeToSystemTime(&t->absolute, &st)) { 289290001Sglebius GetDateFormat(LOCALE_USER_DEFAULT, 0, &st, 290290001Sglebius "ddd',', dd-MMM-yyyy", DateBuf, 50); 291290001Sglebius GetTimeFormat(LOCALE_USER_DEFAULT, 292290001Sglebius TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT, 293290001Sglebius &st, "hh':'mm':'ss", TimeBuf, 50); 294290001Sglebius 295290001Sglebius snprintf(buf, len, "%s %s GMT", DateBuf, TimeBuf); 296290001Sglebius } else { 297290001Sglebius buf[0] = 0; 298290001Sglebius } 299290001Sglebius} 300290001Sglebius 301290001Sglebiusvoid 302290001Sglebiusisc_time_formatISO8601(const isc_time_t *t, char *buf, unsigned int len) { 303290001Sglebius SYSTEMTIME st; 304290001Sglebius char DateBuf[50]; 305290001Sglebius char TimeBuf[50]; 306290001Sglebius 307290001Sglebius/* strtime() format: "%Y-%m-%dT%H:%M:%SZ" */ 308290001Sglebius 309290001Sglebius REQUIRE(len > 0); 310290001Sglebius if (FileTimeToSystemTime(&t->absolute, &st)) { 311290001Sglebius GetDateFormat(LOCALE_NEUTRAL, 0, &st, "yyyy-MM-dd", 312290001Sglebius DateBuf, 50); 313290001Sglebius GetTimeFormat(LOCALE_NEUTRAL, 314290001Sglebius TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT, 315290001Sglebius &st, "hh':'mm':'ss", TimeBuf, 50); 316290001Sglebius snprintf(buf, len, "%s%sZ", DateBuf, TimeBuf); 317290001Sglebius } else { 318290001Sglebius buf[0] = 0; 319290001Sglebius } 320290001Sglebius} 321