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