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