xref: /netbsd-src/external/bsd/ntp/dist/libntp/lib/isc/win32/time.c (revision eabc0478de71e4e011a5b4e0392741e01d491794)
1*eabc0478Schristos /*	$NetBSD: time.c,v 1.2 2024/08/18 20:47:16 christos Exp $	*/
2897be3a4Schristos 
3897be3a4Schristos /*
4897be3a4Schristos  * Copyright (C) 2004, 2006-2009  Internet Systems Consortium, Inc. ("ISC")
5897be3a4Schristos  * Copyright (C) 1998-2001, 2003  Internet Software Consortium.
6897be3a4Schristos  *
7897be3a4Schristos  * Permission to use, copy, modify, and/or distribute this software for any
8897be3a4Schristos  * purpose with or without fee is hereby granted, provided that the above
9897be3a4Schristos  * copyright notice and this permission notice appear in all copies.
10897be3a4Schristos  *
11897be3a4Schristos  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12897be3a4Schristos  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13897be3a4Schristos  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14897be3a4Schristos  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15897be3a4Schristos  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16897be3a4Schristos  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17897be3a4Schristos  * PERFORMANCE OF THIS SOFTWARE.
18897be3a4Schristos  */
19897be3a4Schristos 
20897be3a4Schristos /* Id: time.c,v 1.52 2009/08/14 07:51:08 marka Exp  */
21897be3a4Schristos 
22897be3a4Schristos #include <config.h>
23897be3a4Schristos 
24897be3a4Schristos #include <errno.h>
25897be3a4Schristos #include <limits.h>
26897be3a4Schristos #include <stddef.h>
27897be3a4Schristos #include <stdlib.h>
28897be3a4Schristos #include <string.h>
29897be3a4Schristos #include <time.h>
30897be3a4Schristos 
31897be3a4Schristos #include <windows.h>
32897be3a4Schristos 
33897be3a4Schristos #include <isc/assertions.h>
34897be3a4Schristos #include <isc/time.h>
35897be3a4Schristos #include <isc/util.h>
36897be3a4Schristos 
37897be3a4Schristos /*
38897be3a4Schristos  * struct FILETIME uses "100-nanoseconds intervals".
39897be3a4Schristos  * NS / S = 1000000000 (10^9).
40897be3a4Schristos  * While it is reasonably obvious that this makes the needed
41897be3a4Schristos  * conversion factor 10^7, it is coded this way for additional clarity.
42897be3a4Schristos  */
43897be3a4Schristos #define NS_PER_S 	1000000000
44897be3a4Schristos #define NS_INTERVAL	100
45897be3a4Schristos #define INTERVALS_PER_S (NS_PER_S / NS_INTERVAL)
46897be3a4Schristos #define UINT64_MAX	_UI64_MAX
47897be3a4Schristos 
48897be3a4Schristos /***
49897be3a4Schristos  *** Absolute Times
50897be3a4Schristos  ***/
51897be3a4Schristos 
52897be3a4Schristos static isc_time_t epoch = { { 0, 0 } };
53897be3a4Schristos LIBISC_EXTERNAL_DATA isc_time_t *isc_time_epoch = &epoch;
54897be3a4Schristos 
55897be3a4Schristos /***
56897be3a4Schristos  *** Intervals
57897be3a4Schristos  ***/
58897be3a4Schristos 
59897be3a4Schristos static isc_interval_t zero_interval = { 0 };
60897be3a4Schristos LIBISC_EXTERNAL_DATA isc_interval_t *isc_interval_zero = &zero_interval;
61897be3a4Schristos 
62897be3a4Schristos void
63897be3a4Schristos isc_interval_set(isc_interval_t *i, unsigned int seconds,
64897be3a4Schristos 		 unsigned int nanoseconds)
65897be3a4Schristos {
66897be3a4Schristos 	REQUIRE(i != NULL);
67897be3a4Schristos 	REQUIRE(nanoseconds < NS_PER_S);
68897be3a4Schristos 
69897be3a4Schristos 	/*
70897be3a4Schristos 	 * This rounds nanoseconds up not down.
71897be3a4Schristos 	 */
72897be3a4Schristos 	i->interval = (LONGLONG)seconds * INTERVALS_PER_S
73897be3a4Schristos 		+ (nanoseconds + NS_INTERVAL - 1) / NS_INTERVAL;
74897be3a4Schristos }
75897be3a4Schristos 
76897be3a4Schristos isc_boolean_t
77897be3a4Schristos isc_interval_iszero(const isc_interval_t *i) {
78897be3a4Schristos 	REQUIRE(i != NULL);
79897be3a4Schristos 	if (i->interval == 0)
80897be3a4Schristos 		return (ISC_TRUE);
81897be3a4Schristos 
82897be3a4Schristos 	return (ISC_FALSE);
83897be3a4Schristos }
84897be3a4Schristos 
85897be3a4Schristos void
86897be3a4Schristos isc_time_set(isc_time_t *t, unsigned int seconds, unsigned int nanoseconds) {
87897be3a4Schristos 	SYSTEMTIME epoch = { 1970, 1, 4, 1, 0, 0, 0, 0 };
88897be3a4Schristos 	FILETIME temp;
89897be3a4Schristos 	ULARGE_INTEGER i1;
90897be3a4Schristos 
91897be3a4Schristos 	REQUIRE(t != NULL);
92897be3a4Schristos 	REQUIRE(nanoseconds < NS_PER_S);
93897be3a4Schristos 
94897be3a4Schristos 	SystemTimeToFileTime(&epoch, &temp);
95897be3a4Schristos 
96897be3a4Schristos 	i1.LowPart = t->absolute.dwLowDateTime;
97897be3a4Schristos 	i1.HighPart = t->absolute.dwHighDateTime;
98897be3a4Schristos 
99897be3a4Schristos 	i1.QuadPart += (unsigned __int64)nanoseconds/100;
100897be3a4Schristos 	i1.QuadPart += (unsigned __int64)seconds*10000000;
101897be3a4Schristos 
102897be3a4Schristos 	t->absolute.dwLowDateTime = i1.LowPart;
103897be3a4Schristos 	t->absolute.dwHighDateTime = i1.HighPart;
104897be3a4Schristos }
105897be3a4Schristos 
106897be3a4Schristos void
107897be3a4Schristos isc_time_settoepoch(isc_time_t *t) {
108897be3a4Schristos 	REQUIRE(t != NULL);
109897be3a4Schristos 
110897be3a4Schristos 	t->absolute.dwLowDateTime = 0;
111897be3a4Schristos 	t->absolute.dwHighDateTime = 0;
112897be3a4Schristos }
113897be3a4Schristos 
114897be3a4Schristos isc_boolean_t
115897be3a4Schristos isc_time_isepoch(const isc_time_t *t) {
116897be3a4Schristos 	REQUIRE(t != NULL);
117897be3a4Schristos 
118897be3a4Schristos 	if (t->absolute.dwLowDateTime == 0 &&
119897be3a4Schristos 	    t->absolute.dwHighDateTime == 0)
120897be3a4Schristos 		return (ISC_TRUE);
121897be3a4Schristos 
122897be3a4Schristos 	return (ISC_FALSE);
123897be3a4Schristos }
124897be3a4Schristos 
125897be3a4Schristos isc_result_t
126897be3a4Schristos isc_time_now(isc_time_t *t) {
127897be3a4Schristos 	REQUIRE(t != NULL);
128897be3a4Schristos 
129897be3a4Schristos 	GetSystemTimeAsFileTime(&t->absolute);
130897be3a4Schristos 
131897be3a4Schristos 	return (ISC_R_SUCCESS);
132897be3a4Schristos }
133897be3a4Schristos 
134897be3a4Schristos isc_result_t
135897be3a4Schristos isc_time_nowplusinterval(isc_time_t *t, const isc_interval_t *i) {
136897be3a4Schristos 	ULARGE_INTEGER i1;
137897be3a4Schristos 
138897be3a4Schristos 	REQUIRE(t != NULL);
139897be3a4Schristos 	REQUIRE(i != NULL);
140897be3a4Schristos 
141897be3a4Schristos 	GetSystemTimeAsFileTime(&t->absolute);
142897be3a4Schristos 
143897be3a4Schristos 	i1.LowPart = t->absolute.dwLowDateTime;
144897be3a4Schristos 	i1.HighPart = t->absolute.dwHighDateTime;
145897be3a4Schristos 
146897be3a4Schristos 	if (UINT64_MAX - i1.QuadPart < (unsigned __int64)i->interval)
147897be3a4Schristos 		return (ISC_R_RANGE);
148897be3a4Schristos 
149897be3a4Schristos 	i1.QuadPart += i->interval;
150897be3a4Schristos 
151897be3a4Schristos 	t->absolute.dwLowDateTime  = i1.LowPart;
152897be3a4Schristos 	t->absolute.dwHighDateTime = i1.HighPart;
153897be3a4Schristos 
154897be3a4Schristos 	return (ISC_R_SUCCESS);
155897be3a4Schristos }
156897be3a4Schristos 
157897be3a4Schristos int
158897be3a4Schristos isc_time_compare(const isc_time_t *t1, const isc_time_t *t2) {
159897be3a4Schristos 	REQUIRE(t1 != NULL && t2 != NULL);
160897be3a4Schristos 
161897be3a4Schristos 	return ((int)CompareFileTime(&t1->absolute, &t2->absolute));
162897be3a4Schristos }
163897be3a4Schristos 
164897be3a4Schristos isc_result_t
165897be3a4Schristos isc_time_add(const isc_time_t *t, const isc_interval_t *i, isc_time_t *result)
166897be3a4Schristos {
167897be3a4Schristos 	ULARGE_INTEGER i1;
168897be3a4Schristos 
169897be3a4Schristos 	REQUIRE(t != NULL && i != NULL && result != NULL);
170897be3a4Schristos 
171897be3a4Schristos 	i1.LowPart = t->absolute.dwLowDateTime;
172897be3a4Schristos 	i1.HighPart = t->absolute.dwHighDateTime;
173897be3a4Schristos 
174897be3a4Schristos 	if (UINT64_MAX - i1.QuadPart < (unsigned __int64)i->interval)
175897be3a4Schristos 		return (ISC_R_RANGE);
176897be3a4Schristos 
177897be3a4Schristos 	i1.QuadPart += i->interval;
178897be3a4Schristos 
179897be3a4Schristos 	result->absolute.dwLowDateTime = i1.LowPart;
180897be3a4Schristos 	result->absolute.dwHighDateTime = i1.HighPart;
181897be3a4Schristos 
182897be3a4Schristos 	return (ISC_R_SUCCESS);
183897be3a4Schristos }
184897be3a4Schristos 
185897be3a4Schristos isc_result_t
186897be3a4Schristos isc_time_subtract(const isc_time_t *t, const isc_interval_t *i,
187897be3a4Schristos 		  isc_time_t *result) {
188897be3a4Schristos 	ULARGE_INTEGER i1;
189897be3a4Schristos 
190897be3a4Schristos 	REQUIRE(t != NULL && i != NULL && result != NULL);
191897be3a4Schristos 
192897be3a4Schristos 	i1.LowPart = t->absolute.dwLowDateTime;
193897be3a4Schristos 	i1.HighPart = t->absolute.dwHighDateTime;
194897be3a4Schristos 
195897be3a4Schristos 	if (i1.QuadPart < (unsigned __int64) i->interval)
196897be3a4Schristos 		return (ISC_R_RANGE);
197897be3a4Schristos 
198897be3a4Schristos 	i1.QuadPart -= i->interval;
199897be3a4Schristos 
200897be3a4Schristos 	result->absolute.dwLowDateTime = i1.LowPart;
201897be3a4Schristos 	result->absolute.dwHighDateTime = i1.HighPart;
202897be3a4Schristos 
203897be3a4Schristos 	return (ISC_R_SUCCESS);
204897be3a4Schristos }
205897be3a4Schristos 
206897be3a4Schristos isc_uint64_t
207897be3a4Schristos isc_time_microdiff(const isc_time_t *t1, const isc_time_t *t2) {
208897be3a4Schristos 	ULARGE_INTEGER i1, i2;
209897be3a4Schristos 	LONGLONG i3;
210897be3a4Schristos 
211897be3a4Schristos 	REQUIRE(t1 != NULL && t2 != NULL);
212897be3a4Schristos 
213897be3a4Schristos 	i1.LowPart  = t1->absolute.dwLowDateTime;
214897be3a4Schristos 	i1.HighPart = t1->absolute.dwHighDateTime;
215897be3a4Schristos 	i2.LowPart  = t2->absolute.dwLowDateTime;
216897be3a4Schristos 	i2.HighPart = t2->absolute.dwHighDateTime;
217897be3a4Schristos 
218897be3a4Schristos 	if (i1.QuadPart <= i2.QuadPart)
219897be3a4Schristos 		return (0);
220897be3a4Schristos 
221897be3a4Schristos 	/*
222897be3a4Schristos 	 * Convert to microseconds.
223897be3a4Schristos 	 */
224897be3a4Schristos 	i3 = (i1.QuadPart - i2.QuadPart) / 10;
225897be3a4Schristos 
226897be3a4Schristos 	return (i3);
227897be3a4Schristos }
228897be3a4Schristos 
229897be3a4Schristos isc_uint32_t
230897be3a4Schristos isc_time_seconds(const isc_time_t *t) {
231897be3a4Schristos 	SYSTEMTIME epoch = { 1970, 1, 4, 1, 0, 0, 0, 0 };
232897be3a4Schristos 	FILETIME temp;
233897be3a4Schristos 	ULARGE_INTEGER i1, i2;
234897be3a4Schristos 	LONGLONG i3;
235897be3a4Schristos 
236897be3a4Schristos 	SystemTimeToFileTime(&epoch, &temp);
237897be3a4Schristos 
238897be3a4Schristos 	i1.LowPart  = t->absolute.dwLowDateTime;
239897be3a4Schristos 	i1.HighPart = t->absolute.dwHighDateTime;
240897be3a4Schristos 	i2.LowPart  = temp.dwLowDateTime;
241897be3a4Schristos 	i2.HighPart = temp.dwHighDateTime;
242897be3a4Schristos 
243897be3a4Schristos 	i3 = (i1.QuadPart - i2.QuadPart) / 10000000;
244897be3a4Schristos 
245897be3a4Schristos 	return ((isc_uint32_t)i3);
246897be3a4Schristos }
247897be3a4Schristos 
248897be3a4Schristos isc_uint32_t
249897be3a4Schristos isc_time_nanoseconds(const isc_time_t *t) {
250897be3a4Schristos 	ULARGE_INTEGER i;
251897be3a4Schristos 
252897be3a4Schristos 	i.LowPart  = t->absolute.dwLowDateTime;
253897be3a4Schristos 	i.HighPart = t->absolute.dwHighDateTime;
254897be3a4Schristos 	return ((isc_uint32_t)(i.QuadPart % 10000000) * 100);
255897be3a4Schristos }
256897be3a4Schristos 
257897be3a4Schristos void
258897be3a4Schristos isc_time_formattimestamp(const isc_time_t *t, char *buf, unsigned int len) {
259897be3a4Schristos 	FILETIME localft;
260897be3a4Schristos 	SYSTEMTIME st;
261897be3a4Schristos 	char DateBuf[50];
262897be3a4Schristos 	char TimeBuf[50];
263897be3a4Schristos 
264897be3a4Schristos 	static const char badtime[] = "99-Bad-9999 99:99:99.999";
265897be3a4Schristos 
266897be3a4Schristos 	REQUIRE(len > 0);
267897be3a4Schristos 	if (FileTimeToLocalFileTime(&t->absolute, &localft) &&
268897be3a4Schristos 	    FileTimeToSystemTime(&localft, &st)) {
269897be3a4Schristos 		GetDateFormat(LOCALE_USER_DEFAULT, 0, &st, "dd-MMM-yyyy",
270897be3a4Schristos 			      DateBuf, 50);
271897be3a4Schristos 		GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOTIMEMARKER|
272897be3a4Schristos 			      TIME_FORCE24HOURFORMAT, &st, NULL, TimeBuf, 50);
273897be3a4Schristos 
274897be3a4Schristos 		snprintf(buf, len, "%s %s.%03u", DateBuf, TimeBuf,
275897be3a4Schristos 			 st.wMilliseconds);
276897be3a4Schristos 
277897be3a4Schristos 	} else
278897be3a4Schristos 		snprintf(buf, len, badtime);
279897be3a4Schristos }
280897be3a4Schristos 
281897be3a4Schristos void
282897be3a4Schristos isc_time_formathttptimestamp(const isc_time_t *t, char *buf, unsigned int len) {
283897be3a4Schristos 	SYSTEMTIME st;
284897be3a4Schristos 	char DateBuf[50];
285897be3a4Schristos 	char TimeBuf[50];
286897be3a4Schristos 
287897be3a4Schristos /* strftime() format: "%a, %d %b %Y %H:%M:%S GMT" */
288897be3a4Schristos 
289897be3a4Schristos 	REQUIRE(len > 0);
290897be3a4Schristos 	if (FileTimeToSystemTime(&t->absolute, &st)) {
291897be3a4Schristos 		GetDateFormat(LOCALE_USER_DEFAULT, 0, &st,
292897be3a4Schristos 			      "ddd',', dd-MMM-yyyy", DateBuf, 50);
293897be3a4Schristos 		GetTimeFormat(LOCALE_USER_DEFAULT,
294897be3a4Schristos 			      TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT,
295897be3a4Schristos 			      &st, "hh':'mm':'ss", TimeBuf, 50);
296897be3a4Schristos 
297897be3a4Schristos 		snprintf(buf, len, "%s %s GMT", DateBuf, TimeBuf);
298897be3a4Schristos 	} else {
299897be3a4Schristos 		buf[0] = 0;
300897be3a4Schristos 	}
301897be3a4Schristos }
302897be3a4Schristos 
303897be3a4Schristos void
304897be3a4Schristos isc_time_formatISO8601(const isc_time_t *t, char *buf, unsigned int len) {
305897be3a4Schristos 	SYSTEMTIME st;
306897be3a4Schristos 	char DateBuf[50];
307897be3a4Schristos 	char TimeBuf[50];
308897be3a4Schristos 
309897be3a4Schristos /* strtime() format: "%Y-%m-%dT%H:%M:%SZ" */
310897be3a4Schristos 
311897be3a4Schristos 	REQUIRE(len > 0);
312897be3a4Schristos 	if (FileTimeToSystemTime(&t->absolute, &st)) {
313897be3a4Schristos 		GetDateFormat(LOCALE_NEUTRAL, 0, &st, "yyyy-MM-dd",
314897be3a4Schristos 			      DateBuf, 50);
315897be3a4Schristos 		GetTimeFormat(LOCALE_NEUTRAL,
316897be3a4Schristos 			      TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT,
317897be3a4Schristos 			      &st, "hh':'mm':'ss", TimeBuf, 50);
318897be3a4Schristos 		snprintf(buf, len, "%s%sZ", DateBuf, TimeBuf);
319897be3a4Schristos 	} else {
320897be3a4Schristos 		buf[0] = 0;
321897be3a4Schristos 	}
322897be3a4Schristos }
323