1258945Sroberto/* 2280849Scy * Copyright (C) 2004, 2006-2009 Internet Systems Consortium, Inc. ("ISC") 3258945Sroberto * Copyright (C) 1998-2001, 2003 Internet Software Consortium. 4258945Sroberto * 5258945Sroberto * Permission to use, copy, modify, and/or distribute this software for any 6258945Sroberto * purpose with or without fee is hereby granted, provided that the above 7258945Sroberto * copyright notice and this permission notice appear in all copies. 8258945Sroberto * 9258945Sroberto * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10258945Sroberto * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11258945Sroberto * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12258945Sroberto * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13258945Sroberto * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14258945Sroberto * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15258945Sroberto * PERFORMANCE OF THIS SOFTWARE. 16258945Sroberto */ 17258945Sroberto 18280849Scy/* $Id: time.c,v 1.52 2009/08/14 07:51:08 marka Exp $ */ 19258945Sroberto 20258945Sroberto#include <config.h> 21258945Sroberto 22258945Sroberto#include <errno.h> 23258945Sroberto#include <limits.h> 24258945Sroberto#include <stddef.h> 25258945Sroberto#include <stdlib.h> 26258945Sroberto#include <string.h> 27258945Sroberto#include <time.h> 28258945Sroberto 29258945Sroberto#include <windows.h> 30258945Sroberto 31258945Sroberto#include <isc/assertions.h> 32258945Sroberto#include <isc/time.h> 33258945Sroberto#include <isc/util.h> 34258945Sroberto 35258945Sroberto/* 36258945Sroberto * struct FILETIME uses "100-nanoseconds intervals". 37258945Sroberto * NS / S = 1000000000 (10^9). 38258945Sroberto * While it is reasonably obvious that this makes the needed 39258945Sroberto * conversion factor 10^7, it is coded this way for additional clarity. 40258945Sroberto */ 41258945Sroberto#define NS_PER_S 1000000000 42258945Sroberto#define NS_INTERVAL 100 43258945Sroberto#define INTERVALS_PER_S (NS_PER_S / NS_INTERVAL) 44258945Sroberto#define UINT64_MAX _UI64_MAX 45258945Sroberto 46258945Sroberto/*** 47258945Sroberto *** Absolute Times 48258945Sroberto ***/ 49258945Sroberto 50258945Srobertostatic isc_time_t epoch = { { 0, 0 } }; 51258945SrobertoLIBISC_EXTERNAL_DATA isc_time_t *isc_time_epoch = &epoch; 52258945Sroberto 53258945Sroberto/*** 54258945Sroberto *** Intervals 55258945Sroberto ***/ 56258945Sroberto 57258945Srobertostatic isc_interval_t zero_interval = { 0 }; 58258945SrobertoLIBISC_EXTERNAL_DATA isc_interval_t *isc_interval_zero = &zero_interval; 59258945Sroberto 60258945Srobertovoid 61258945Srobertoisc_interval_set(isc_interval_t *i, unsigned int seconds, 62258945Sroberto unsigned int nanoseconds) 63258945Sroberto{ 64258945Sroberto REQUIRE(i != NULL); 65258945Sroberto REQUIRE(nanoseconds < NS_PER_S); 66258945Sroberto 67258945Sroberto /* 68258945Sroberto * This rounds nanoseconds up not down. 69258945Sroberto */ 70258945Sroberto i->interval = (LONGLONG)seconds * INTERVALS_PER_S 71258945Sroberto + (nanoseconds + NS_INTERVAL - 1) / NS_INTERVAL; 72258945Sroberto} 73258945Sroberto 74258945Srobertoisc_boolean_t 75258945Srobertoisc_interval_iszero(const isc_interval_t *i) { 76258945Sroberto REQUIRE(i != NULL); 77258945Sroberto if (i->interval == 0) 78258945Sroberto return (ISC_TRUE); 79258945Sroberto 80258945Sroberto return (ISC_FALSE); 81258945Sroberto} 82258945Sroberto 83258945Srobertovoid 84258945Srobertoisc_time_set(isc_time_t *t, unsigned int seconds, unsigned int nanoseconds) { 85258945Sroberto SYSTEMTIME epoch = { 1970, 1, 4, 1, 0, 0, 0, 0 }; 86258945Sroberto FILETIME temp; 87258945Sroberto ULARGE_INTEGER i1; 88258945Sroberto 89258945Sroberto REQUIRE(t != NULL); 90258945Sroberto REQUIRE(nanoseconds < NS_PER_S); 91258945Sroberto 92258945Sroberto SystemTimeToFileTime(&epoch, &temp); 93258945Sroberto 94258945Sroberto i1.LowPart = t->absolute.dwLowDateTime; 95258945Sroberto i1.HighPart = t->absolute.dwHighDateTime; 96258945Sroberto 97258945Sroberto i1.QuadPart += (unsigned __int64)nanoseconds/100; 98258945Sroberto i1.QuadPart += (unsigned __int64)seconds*10000000; 99258945Sroberto 100258945Sroberto t->absolute.dwLowDateTime = i1.LowPart; 101258945Sroberto t->absolute.dwHighDateTime = i1.HighPart; 102258945Sroberto} 103258945Sroberto 104258945Srobertovoid 105258945Srobertoisc_time_settoepoch(isc_time_t *t) { 106258945Sroberto REQUIRE(t != NULL); 107258945Sroberto 108258945Sroberto t->absolute.dwLowDateTime = 0; 109258945Sroberto t->absolute.dwHighDateTime = 0; 110258945Sroberto} 111258945Sroberto 112258945Srobertoisc_boolean_t 113258945Srobertoisc_time_isepoch(const isc_time_t *t) { 114258945Sroberto REQUIRE(t != NULL); 115258945Sroberto 116258945Sroberto if (t->absolute.dwLowDateTime == 0 && 117258945Sroberto t->absolute.dwHighDateTime == 0) 118258945Sroberto return (ISC_TRUE); 119258945Sroberto 120258945Sroberto return (ISC_FALSE); 121258945Sroberto} 122258945Sroberto 123258945Srobertoisc_result_t 124258945Srobertoisc_time_now(isc_time_t *t) { 125258945Sroberto REQUIRE(t != NULL); 126258945Sroberto 127258945Sroberto GetSystemTimeAsFileTime(&t->absolute); 128258945Sroberto 129258945Sroberto return (ISC_R_SUCCESS); 130258945Sroberto} 131258945Sroberto 132258945Srobertoisc_result_t 133258945Srobertoisc_time_nowplusinterval(isc_time_t *t, const isc_interval_t *i) { 134258945Sroberto ULARGE_INTEGER i1; 135258945Sroberto 136258945Sroberto REQUIRE(t != NULL); 137258945Sroberto REQUIRE(i != NULL); 138258945Sroberto 139258945Sroberto GetSystemTimeAsFileTime(&t->absolute); 140258945Sroberto 141258945Sroberto i1.LowPart = t->absolute.dwLowDateTime; 142258945Sroberto i1.HighPart = t->absolute.dwHighDateTime; 143258945Sroberto 144258945Sroberto if (UINT64_MAX - i1.QuadPart < (unsigned __int64)i->interval) 145258945Sroberto return (ISC_R_RANGE); 146258945Sroberto 147258945Sroberto i1.QuadPart += i->interval; 148258945Sroberto 149258945Sroberto t->absolute.dwLowDateTime = i1.LowPart; 150258945Sroberto t->absolute.dwHighDateTime = i1.HighPart; 151258945Sroberto 152258945Sroberto return (ISC_R_SUCCESS); 153258945Sroberto} 154258945Sroberto 155258945Srobertoint 156258945Srobertoisc_time_compare(const isc_time_t *t1, const isc_time_t *t2) { 157258945Sroberto REQUIRE(t1 != NULL && t2 != NULL); 158258945Sroberto 159258945Sroberto return ((int)CompareFileTime(&t1->absolute, &t2->absolute)); 160258945Sroberto} 161258945Sroberto 162258945Srobertoisc_result_t 163258945Srobertoisc_time_add(const isc_time_t *t, const isc_interval_t *i, isc_time_t *result) 164258945Sroberto{ 165258945Sroberto ULARGE_INTEGER i1; 166258945Sroberto 167258945Sroberto REQUIRE(t != NULL && i != NULL && result != NULL); 168258945Sroberto 169258945Sroberto i1.LowPart = t->absolute.dwLowDateTime; 170258945Sroberto i1.HighPart = t->absolute.dwHighDateTime; 171258945Sroberto 172258945Sroberto if (UINT64_MAX - i1.QuadPart < (unsigned __int64)i->interval) 173258945Sroberto return (ISC_R_RANGE); 174258945Sroberto 175258945Sroberto i1.QuadPart += i->interval; 176258945Sroberto 177258945Sroberto result->absolute.dwLowDateTime = i1.LowPart; 178258945Sroberto result->absolute.dwHighDateTime = i1.HighPart; 179258945Sroberto 180258945Sroberto return (ISC_R_SUCCESS); 181258945Sroberto} 182258945Sroberto 183258945Srobertoisc_result_t 184258945Srobertoisc_time_subtract(const isc_time_t *t, const isc_interval_t *i, 185258945Sroberto isc_time_t *result) { 186258945Sroberto ULARGE_INTEGER i1; 187258945Sroberto 188258945Sroberto REQUIRE(t != NULL && i != NULL && result != NULL); 189258945Sroberto 190258945Sroberto i1.LowPart = t->absolute.dwLowDateTime; 191258945Sroberto i1.HighPart = t->absolute.dwHighDateTime; 192258945Sroberto 193258945Sroberto if (i1.QuadPart < (unsigned __int64) i->interval) 194258945Sroberto return (ISC_R_RANGE); 195258945Sroberto 196258945Sroberto i1.QuadPart -= i->interval; 197258945Sroberto 198258945Sroberto result->absolute.dwLowDateTime = i1.LowPart; 199258945Sroberto result->absolute.dwHighDateTime = i1.HighPart; 200258945Sroberto 201258945Sroberto return (ISC_R_SUCCESS); 202258945Sroberto} 203258945Sroberto 204258945Srobertoisc_uint64_t 205258945Srobertoisc_time_microdiff(const isc_time_t *t1, const isc_time_t *t2) { 206258945Sroberto ULARGE_INTEGER i1, i2; 207258945Sroberto LONGLONG i3; 208258945Sroberto 209258945Sroberto REQUIRE(t1 != NULL && t2 != NULL); 210258945Sroberto 211258945Sroberto i1.LowPart = t1->absolute.dwLowDateTime; 212258945Sroberto i1.HighPart = t1->absolute.dwHighDateTime; 213258945Sroberto i2.LowPart = t2->absolute.dwLowDateTime; 214258945Sroberto i2.HighPart = t2->absolute.dwHighDateTime; 215258945Sroberto 216258945Sroberto if (i1.QuadPart <= i2.QuadPart) 217258945Sroberto return (0); 218258945Sroberto 219258945Sroberto /* 220258945Sroberto * Convert to microseconds. 221258945Sroberto */ 222258945Sroberto i3 = (i1.QuadPart - i2.QuadPart) / 10; 223258945Sroberto 224258945Sroberto return (i3); 225258945Sroberto} 226258945Sroberto 227258945Srobertoisc_uint32_t 228258945Srobertoisc_time_seconds(const isc_time_t *t) { 229280849Scy SYSTEMTIME epoch = { 1970, 1, 4, 1, 0, 0, 0, 0 }; 230280849Scy FILETIME temp; 231280849Scy ULARGE_INTEGER i1, i2; 232280849Scy LONGLONG i3; 233258945Sroberto 234280849Scy SystemTimeToFileTime(&epoch, &temp); 235258945Sroberto 236280849Scy i1.LowPart = t->absolute.dwLowDateTime; 237280849Scy i1.HighPart = t->absolute.dwHighDateTime; 238280849Scy i2.LowPart = temp.dwLowDateTime; 239280849Scy i2.HighPart = temp.dwHighDateTime; 240280849Scy 241280849Scy i3 = (i1.QuadPart - i2.QuadPart) / 10000000; 242280849Scy 243280849Scy return ((isc_uint32_t)i3); 244258945Sroberto} 245258945Sroberto 246258945Srobertoisc_uint32_t 247258945Srobertoisc_time_nanoseconds(const isc_time_t *t) { 248280849Scy ULARGE_INTEGER i; 249258945Sroberto 250280849Scy i.LowPart = t->absolute.dwLowDateTime; 251280849Scy i.HighPart = t->absolute.dwHighDateTime; 252280849Scy return ((isc_uint32_t)(i.QuadPart % 10000000) * 100); 253258945Sroberto} 254258945Sroberto 255258945Srobertovoid 256258945Srobertoisc_time_formattimestamp(const isc_time_t *t, char *buf, unsigned int len) { 257258945Sroberto FILETIME localft; 258258945Sroberto SYSTEMTIME st; 259258945Sroberto char DateBuf[50]; 260258945Sroberto char TimeBuf[50]; 261258945Sroberto 262258945Sroberto static const char badtime[] = "99-Bad-9999 99:99:99.999"; 263258945Sroberto 264258945Sroberto REQUIRE(len > 0); 265258945Sroberto if (FileTimeToLocalFileTime(&t->absolute, &localft) && 266258945Sroberto FileTimeToSystemTime(&localft, &st)) { 267258945Sroberto GetDateFormat(LOCALE_USER_DEFAULT, 0, &st, "dd-MMM-yyyy", 268258945Sroberto DateBuf, 50); 269258945Sroberto GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOTIMEMARKER| 270258945Sroberto TIME_FORCE24HOURFORMAT, &st, NULL, TimeBuf, 50); 271258945Sroberto 272258945Sroberto snprintf(buf, len, "%s %s.%03u", DateBuf, TimeBuf, 273258945Sroberto st.wMilliseconds); 274258945Sroberto 275258945Sroberto } else 276258945Sroberto snprintf(buf, len, badtime); 277258945Sroberto} 278258945Sroberto 279258945Srobertovoid 280258945Srobertoisc_time_formathttptimestamp(const isc_time_t *t, char *buf, unsigned int len) { 281258945Sroberto SYSTEMTIME st; 282258945Sroberto char DateBuf[50]; 283258945Sroberto char TimeBuf[50]; 284258945Sroberto 285280849Scy/* strftime() format: "%a, %d %b %Y %H:%M:%S GMT" */ 286280849Scy 287258945Sroberto REQUIRE(len > 0); 288258945Sroberto if (FileTimeToSystemTime(&t->absolute, &st)) { 289280849Scy GetDateFormat(LOCALE_USER_DEFAULT, 0, &st, 290280849Scy "ddd',', dd-MMM-yyyy", DateBuf, 50); 291258945Sroberto GetTimeFormat(LOCALE_USER_DEFAULT, 292258945Sroberto TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT, 293258945Sroberto &st, "hh':'mm':'ss", TimeBuf, 50); 294258945Sroberto 295258945Sroberto snprintf(buf, len, "%s %s GMT", DateBuf, TimeBuf); 296258945Sroberto } else { 297258945Sroberto buf[0] = 0; 298258945Sroberto } 299258945Sroberto} 300280849Scy 301280849Scyvoid 302280849Scyisc_time_formatISO8601(const isc_time_t *t, char *buf, unsigned int len) { 303280849Scy SYSTEMTIME st; 304280849Scy char DateBuf[50]; 305280849Scy char TimeBuf[50]; 306280849Scy 307280849Scy/* strtime() format: "%Y-%m-%dT%H:%M:%SZ" */ 308280849Scy 309280849Scy REQUIRE(len > 0); 310280849Scy if (FileTimeToSystemTime(&t->absolute, &st)) { 311280849Scy GetDateFormat(LOCALE_NEUTRAL, 0, &st, "yyyy-MM-dd", 312280849Scy DateBuf, 50); 313280849Scy GetTimeFormat(LOCALE_NEUTRAL, 314280849Scy TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT, 315280849Scy &st, "hh':'mm':'ss", TimeBuf, 50); 316280849Scy snprintf(buf, len, "%s%sZ", DateBuf, TimeBuf); 317280849Scy } else { 318280849Scy buf[0] = 0; 319280849Scy } 320280849Scy} 321