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