xref: /netbsd-src/external/mpl/dhcp/bind/dist/lib/isc/unix/time.c (revision 4afad4b7fa6d4a0d3dedf41d1587a7250710ae54)
1*4afad4b7Schristos /*	$NetBSD: time.c,v 1.1 2024/02/18 20:57:57 christos Exp $	*/
2*4afad4b7Schristos 
3*4afad4b7Schristos /*
4*4afad4b7Schristos  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5*4afad4b7Schristos  *
6*4afad4b7Schristos  * SPDX-License-Identifier: MPL-2.0
7*4afad4b7Schristos  *
8*4afad4b7Schristos  * This Source Code Form is subject to the terms of the Mozilla Public
9*4afad4b7Schristos  * License, v. 2.0. If a copy of the MPL was not distributed with this
10*4afad4b7Schristos  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
11*4afad4b7Schristos  *
12*4afad4b7Schristos  * See the COPYRIGHT file distributed with this work for additional
13*4afad4b7Schristos  * information regarding copyright ownership.
14*4afad4b7Schristos  */
15*4afad4b7Schristos 
16*4afad4b7Schristos /*! \file */
17*4afad4b7Schristos 
18*4afad4b7Schristos #include <errno.h>
19*4afad4b7Schristos #include <inttypes.h>
20*4afad4b7Schristos #include <limits.h>
21*4afad4b7Schristos #include <stdbool.h>
22*4afad4b7Schristos #include <stdlib.h>
23*4afad4b7Schristos #include <sys/time.h> /* Required for struct timeval on some platforms. */
24*4afad4b7Schristos #include <syslog.h>
25*4afad4b7Schristos #include <time.h>
26*4afad4b7Schristos 
27*4afad4b7Schristos #include <isc/log.h>
28*4afad4b7Schristos #include <isc/platform.h>
29*4afad4b7Schristos #include <isc/print.h>
30*4afad4b7Schristos #include <isc/strerr.h>
31*4afad4b7Schristos #include <isc/string.h>
32*4afad4b7Schristos #include <isc/time.h>
33*4afad4b7Schristos #include <isc/tm.h>
34*4afad4b7Schristos #include <isc/util.h>
35*4afad4b7Schristos 
36*4afad4b7Schristos #define NS_PER_S  1000000000 /*%< Nanoseconds per second. */
37*4afad4b7Schristos #define NS_PER_US 1000	     /*%< Nanoseconds per microsecond. */
38*4afad4b7Schristos #define NS_PER_MS 1000000    /*%< Nanoseconds per millisecond. */
39*4afad4b7Schristos 
40*4afad4b7Schristos #if defined(CLOCK_REALTIME)
41*4afad4b7Schristos #define CLOCKSOURCE_HIRES CLOCK_REALTIME
42*4afad4b7Schristos #endif /* #if defined(CLOCK_REALTIME) */
43*4afad4b7Schristos 
44*4afad4b7Schristos #if defined(CLOCK_REALTIME_COARSE)
45*4afad4b7Schristos #define CLOCKSOURCE CLOCK_REALTIME_COARSE
46*4afad4b7Schristos #elif defined(CLOCK_REALTIME_FAST)
47*4afad4b7Schristos #define CLOCKSOURCE CLOCK_REALTIME_FAST
48*4afad4b7Schristos #else /* if defined(CLOCK_REALTIME_COARSE) */
49*4afad4b7Schristos #define CLOCKSOURCE CLOCK_REALTIME
50*4afad4b7Schristos #endif /* if defined(CLOCK_REALTIME_COARSE) */
51*4afad4b7Schristos 
52*4afad4b7Schristos #if !defined(CLOCKSOURCE_HIRES)
53*4afad4b7Schristos #define CLOCKSOURCE_HIRES CLOCKSOURCE
54*4afad4b7Schristos #endif /* #ifndef CLOCKSOURCE_HIRES */
55*4afad4b7Schristos 
56*4afad4b7Schristos /*%
57*4afad4b7Schristos  *** Intervals
58*4afad4b7Schristos  ***/
59*4afad4b7Schristos 
60*4afad4b7Schristos #if !defined(UNIT_TESTING)
61*4afad4b7Schristos static const isc_interval_t zero_interval = { 0, 0 };
62*4afad4b7Schristos const isc_interval_t *const isc_interval_zero = &zero_interval;
63*4afad4b7Schristos #endif
64*4afad4b7Schristos 
65*4afad4b7Schristos void
isc_interval_set(isc_interval_t * i,unsigned int seconds,unsigned int nanoseconds)66*4afad4b7Schristos isc_interval_set(isc_interval_t *i, unsigned int seconds,
67*4afad4b7Schristos 		 unsigned int nanoseconds) {
68*4afad4b7Schristos 	REQUIRE(i != NULL);
69*4afad4b7Schristos 	REQUIRE(nanoseconds < NS_PER_S);
70*4afad4b7Schristos 
71*4afad4b7Schristos 	i->seconds = seconds;
72*4afad4b7Schristos 	i->nanoseconds = nanoseconds;
73*4afad4b7Schristos }
74*4afad4b7Schristos 
75*4afad4b7Schristos bool
isc_interval_iszero(const isc_interval_t * i)76*4afad4b7Schristos isc_interval_iszero(const isc_interval_t *i) {
77*4afad4b7Schristos 	REQUIRE(i != NULL);
78*4afad4b7Schristos 	INSIST(i->nanoseconds < NS_PER_S);
79*4afad4b7Schristos 
80*4afad4b7Schristos 	if (i->seconds == 0 && i->nanoseconds == 0) {
81*4afad4b7Schristos 		return (true);
82*4afad4b7Schristos 	}
83*4afad4b7Schristos 
84*4afad4b7Schristos 	return (false);
85*4afad4b7Schristos }
86*4afad4b7Schristos 
87*4afad4b7Schristos /***
88*4afad4b7Schristos  *** Absolute Times
89*4afad4b7Schristos  ***/
90*4afad4b7Schristos 
91*4afad4b7Schristos #if !defined(UNIT_TESTING)
92*4afad4b7Schristos static const isc_time_t epoch = { 0, 0 };
93*4afad4b7Schristos const isc_time_t *const isc_time_epoch = &epoch;
94*4afad4b7Schristos #endif
95*4afad4b7Schristos 
96*4afad4b7Schristos void
isc_time_set(isc_time_t * t,unsigned int seconds,unsigned int nanoseconds)97*4afad4b7Schristos isc_time_set(isc_time_t *t, unsigned int seconds, unsigned int nanoseconds) {
98*4afad4b7Schristos 	REQUIRE(t != NULL);
99*4afad4b7Schristos 	REQUIRE(nanoseconds < NS_PER_S);
100*4afad4b7Schristos 
101*4afad4b7Schristos 	t->seconds = seconds;
102*4afad4b7Schristos 	t->nanoseconds = nanoseconds;
103*4afad4b7Schristos }
104*4afad4b7Schristos 
105*4afad4b7Schristos void
isc_time_settoepoch(isc_time_t * t)106*4afad4b7Schristos isc_time_settoepoch(isc_time_t *t) {
107*4afad4b7Schristos 	REQUIRE(t != NULL);
108*4afad4b7Schristos 
109*4afad4b7Schristos 	t->seconds = 0;
110*4afad4b7Schristos 	t->nanoseconds = 0;
111*4afad4b7Schristos }
112*4afad4b7Schristos 
113*4afad4b7Schristos bool
isc_time_isepoch(const isc_time_t * t)114*4afad4b7Schristos isc_time_isepoch(const isc_time_t *t) {
115*4afad4b7Schristos 	REQUIRE(t != NULL);
116*4afad4b7Schristos 	INSIST(t->nanoseconds < NS_PER_S);
117*4afad4b7Schristos 
118*4afad4b7Schristos 	if (t->seconds == 0 && t->nanoseconds == 0) {
119*4afad4b7Schristos 		return (true);
120*4afad4b7Schristos 	}
121*4afad4b7Schristos 
122*4afad4b7Schristos 	return (false);
123*4afad4b7Schristos }
124*4afad4b7Schristos 
125*4afad4b7Schristos static isc_result_t
time_now(isc_time_t * t,clockid_t clock)126*4afad4b7Schristos time_now(isc_time_t *t, clockid_t clock) {
127*4afad4b7Schristos 	struct timespec ts;
128*4afad4b7Schristos 	char strbuf[ISC_STRERRORSIZE];
129*4afad4b7Schristos 
130*4afad4b7Schristos 	REQUIRE(t != NULL);
131*4afad4b7Schristos 
132*4afad4b7Schristos 	if (clock_gettime(clock, &ts) == -1) {
133*4afad4b7Schristos 		strerror_r(errno, strbuf, sizeof(strbuf));
134*4afad4b7Schristos 		UNEXPECTED_ERROR(__FILE__, __LINE__, "%s", strbuf);
135*4afad4b7Schristos 		return (ISC_R_UNEXPECTED);
136*4afad4b7Schristos 	}
137*4afad4b7Schristos 
138*4afad4b7Schristos 	if (ts.tv_sec < 0 || ts.tv_nsec < 0 || ts.tv_nsec >= NS_PER_S) {
139*4afad4b7Schristos 		return (ISC_R_UNEXPECTED);
140*4afad4b7Schristos 	}
141*4afad4b7Schristos 
142*4afad4b7Schristos 	/*
143*4afad4b7Schristos 	 * Ensure the tv_sec value fits in t->seconds.
144*4afad4b7Schristos 	 */
145*4afad4b7Schristos 	if (sizeof(ts.tv_sec) > sizeof(t->seconds) &&
146*4afad4b7Schristos 	    ((ts.tv_sec | (unsigned int)-1) ^ (unsigned int)-1) != 0U)
147*4afad4b7Schristos 	{
148*4afad4b7Schristos 		return (ISC_R_RANGE);
149*4afad4b7Schristos 	}
150*4afad4b7Schristos 
151*4afad4b7Schristos 	t->seconds = ts.tv_sec;
152*4afad4b7Schristos 	t->nanoseconds = ts.tv_nsec;
153*4afad4b7Schristos 
154*4afad4b7Schristos 	return (ISC_R_SUCCESS);
155*4afad4b7Schristos }
156*4afad4b7Schristos 
157*4afad4b7Schristos isc_result_t
isc_time_now_hires(isc_time_t * t)158*4afad4b7Schristos isc_time_now_hires(isc_time_t *t) {
159*4afad4b7Schristos 	return time_now(t, CLOCKSOURCE_HIRES);
160*4afad4b7Schristos }
161*4afad4b7Schristos 
162*4afad4b7Schristos isc_result_t
isc_time_now(isc_time_t * t)163*4afad4b7Schristos isc_time_now(isc_time_t *t) {
164*4afad4b7Schristos 	return time_now(t, CLOCKSOURCE);
165*4afad4b7Schristos }
166*4afad4b7Schristos 
167*4afad4b7Schristos isc_result_t
isc_time_nowplusinterval(isc_time_t * t,const isc_interval_t * i)168*4afad4b7Schristos isc_time_nowplusinterval(isc_time_t *t, const isc_interval_t *i) {
169*4afad4b7Schristos 	struct timespec ts;
170*4afad4b7Schristos 	char strbuf[ISC_STRERRORSIZE];
171*4afad4b7Schristos 
172*4afad4b7Schristos 	REQUIRE(t != NULL);
173*4afad4b7Schristos 	REQUIRE(i != NULL);
174*4afad4b7Schristos 	INSIST(i->nanoseconds < NS_PER_S);
175*4afad4b7Schristos 
176*4afad4b7Schristos 	if (clock_gettime(CLOCKSOURCE, &ts) == -1) {
177*4afad4b7Schristos 		strerror_r(errno, strbuf, sizeof(strbuf));
178*4afad4b7Schristos 		UNEXPECTED_ERROR(__FILE__, __LINE__, "%s", strbuf);
179*4afad4b7Schristos 		return (ISC_R_UNEXPECTED);
180*4afad4b7Schristos 	}
181*4afad4b7Schristos 
182*4afad4b7Schristos 	if (ts.tv_sec < 0 || ts.tv_nsec < 0 || ts.tv_nsec >= NS_PER_S) {
183*4afad4b7Schristos 		return (ISC_R_UNEXPECTED);
184*4afad4b7Schristos 	}
185*4afad4b7Schristos 
186*4afad4b7Schristos 	/*
187*4afad4b7Schristos 	 * Ensure the resulting seconds value fits in the size of an
188*4afad4b7Schristos 	 * unsigned int.  (It is written this way as a slight optimization;
189*4afad4b7Schristos 	 * note that even if both values == INT_MAX, then when added
190*4afad4b7Schristos 	 * and getting another 1 added below the result is UINT_MAX.)
191*4afad4b7Schristos 	 */
192*4afad4b7Schristos 	if ((ts.tv_sec > INT_MAX || i->seconds > INT_MAX) &&
193*4afad4b7Schristos 	    ((long long)ts.tv_sec + i->seconds > UINT_MAX))
194*4afad4b7Schristos 	{
195*4afad4b7Schristos 		return (ISC_R_RANGE);
196*4afad4b7Schristos 	}
197*4afad4b7Schristos 
198*4afad4b7Schristos 	t->seconds = ts.tv_sec + i->seconds;
199*4afad4b7Schristos 	t->nanoseconds = ts.tv_nsec + i->nanoseconds;
200*4afad4b7Schristos 	if (t->nanoseconds >= NS_PER_S) {
201*4afad4b7Schristos 		t->seconds++;
202*4afad4b7Schristos 		t->nanoseconds -= NS_PER_S;
203*4afad4b7Schristos 	}
204*4afad4b7Schristos 
205*4afad4b7Schristos 	return (ISC_R_SUCCESS);
206*4afad4b7Schristos }
207*4afad4b7Schristos 
208*4afad4b7Schristos int
isc_time_compare(const isc_time_t * t1,const isc_time_t * t2)209*4afad4b7Schristos isc_time_compare(const isc_time_t *t1, const isc_time_t *t2) {
210*4afad4b7Schristos 	REQUIRE(t1 != NULL && t2 != NULL);
211*4afad4b7Schristos 	INSIST(t1->nanoseconds < NS_PER_S && t2->nanoseconds < NS_PER_S);
212*4afad4b7Schristos 
213*4afad4b7Schristos 	if (t1->seconds < t2->seconds) {
214*4afad4b7Schristos 		return (-1);
215*4afad4b7Schristos 	}
216*4afad4b7Schristos 	if (t1->seconds > t2->seconds) {
217*4afad4b7Schristos 		return (1);
218*4afad4b7Schristos 	}
219*4afad4b7Schristos 	if (t1->nanoseconds < t2->nanoseconds) {
220*4afad4b7Schristos 		return (-1);
221*4afad4b7Schristos 	}
222*4afad4b7Schristos 	if (t1->nanoseconds > t2->nanoseconds) {
223*4afad4b7Schristos 		return (1);
224*4afad4b7Schristos 	}
225*4afad4b7Schristos 	return (0);
226*4afad4b7Schristos }
227*4afad4b7Schristos 
228*4afad4b7Schristos isc_result_t
isc_time_add(const isc_time_t * t,const isc_interval_t * i,isc_time_t * result)229*4afad4b7Schristos isc_time_add(const isc_time_t *t, const isc_interval_t *i, isc_time_t *result) {
230*4afad4b7Schristos 	REQUIRE(t != NULL && i != NULL && result != NULL);
231*4afad4b7Schristos 	REQUIRE(t->nanoseconds < NS_PER_S && i->nanoseconds < NS_PER_S);
232*4afad4b7Schristos 
233*4afad4b7Schristos 	/* Seconds */
234*4afad4b7Schristos 	if (t->seconds > UINT_MAX - i->seconds) {
235*4afad4b7Schristos 		return (ISC_R_RANGE);
236*4afad4b7Schristos 	}
237*4afad4b7Schristos 	result->seconds = t->seconds + i->seconds;
238*4afad4b7Schristos 
239*4afad4b7Schristos 	/* Nanoseconds */
240*4afad4b7Schristos 	result->nanoseconds = t->nanoseconds + i->nanoseconds;
241*4afad4b7Schristos 	if (result->nanoseconds >= NS_PER_S) {
242*4afad4b7Schristos 		if (result->seconds == UINT_MAX) {
243*4afad4b7Schristos 			return (ISC_R_RANGE);
244*4afad4b7Schristos 		}
245*4afad4b7Schristos 		result->nanoseconds -= NS_PER_S;
246*4afad4b7Schristos 		result->seconds++;
247*4afad4b7Schristos 	}
248*4afad4b7Schristos 
249*4afad4b7Schristos 	return (ISC_R_SUCCESS);
250*4afad4b7Schristos }
251*4afad4b7Schristos 
252*4afad4b7Schristos isc_result_t
isc_time_subtract(const isc_time_t * t,const isc_interval_t * i,isc_time_t * result)253*4afad4b7Schristos isc_time_subtract(const isc_time_t *t, const isc_interval_t *i,
254*4afad4b7Schristos 		  isc_time_t *result) {
255*4afad4b7Schristos 	REQUIRE(t != NULL && i != NULL && result != NULL);
256*4afad4b7Schristos 	REQUIRE(t->nanoseconds < NS_PER_S && i->nanoseconds < NS_PER_S);
257*4afad4b7Schristos 
258*4afad4b7Schristos 	/* Seconds */
259*4afad4b7Schristos 	if (t->seconds < i->seconds) {
260*4afad4b7Schristos 		return (ISC_R_RANGE);
261*4afad4b7Schristos 	}
262*4afad4b7Schristos 	result->seconds = t->seconds - i->seconds;
263*4afad4b7Schristos 
264*4afad4b7Schristos 	/* Nanoseconds */
265*4afad4b7Schristos 	if (t->nanoseconds >= i->nanoseconds) {
266*4afad4b7Schristos 		result->nanoseconds = t->nanoseconds - i->nanoseconds;
267*4afad4b7Schristos 	} else {
268*4afad4b7Schristos 		if (result->seconds == 0) {
269*4afad4b7Schristos 			return (ISC_R_RANGE);
270*4afad4b7Schristos 		}
271*4afad4b7Schristos 		result->seconds--;
272*4afad4b7Schristos 		result->nanoseconds = NS_PER_S + t->nanoseconds -
273*4afad4b7Schristos 				      i->nanoseconds;
274*4afad4b7Schristos 	}
275*4afad4b7Schristos 
276*4afad4b7Schristos 	return (ISC_R_SUCCESS);
277*4afad4b7Schristos }
278*4afad4b7Schristos 
279*4afad4b7Schristos uint64_t
isc_time_microdiff(const isc_time_t * t1,const isc_time_t * t2)280*4afad4b7Schristos isc_time_microdiff(const isc_time_t *t1, const isc_time_t *t2) {
281*4afad4b7Schristos 	uint64_t i1, i2, i3;
282*4afad4b7Schristos 
283*4afad4b7Schristos 	REQUIRE(t1 != NULL && t2 != NULL);
284*4afad4b7Schristos 	INSIST(t1->nanoseconds < NS_PER_S && t2->nanoseconds < NS_PER_S);
285*4afad4b7Schristos 
286*4afad4b7Schristos 	i1 = (uint64_t)t1->seconds * NS_PER_S + t1->nanoseconds;
287*4afad4b7Schristos 	i2 = (uint64_t)t2->seconds * NS_PER_S + t2->nanoseconds;
288*4afad4b7Schristos 
289*4afad4b7Schristos 	if (i1 <= i2) {
290*4afad4b7Schristos 		return (0);
291*4afad4b7Schristos 	}
292*4afad4b7Schristos 
293*4afad4b7Schristos 	i3 = i1 - i2;
294*4afad4b7Schristos 
295*4afad4b7Schristos 	/*
296*4afad4b7Schristos 	 * Convert to microseconds.
297*4afad4b7Schristos 	 */
298*4afad4b7Schristos 	i3 /= NS_PER_US;
299*4afad4b7Schristos 
300*4afad4b7Schristos 	return (i3);
301*4afad4b7Schristos }
302*4afad4b7Schristos 
303*4afad4b7Schristos uint32_t
isc_time_seconds(const isc_time_t * t)304*4afad4b7Schristos isc_time_seconds(const isc_time_t *t) {
305*4afad4b7Schristos 	REQUIRE(t != NULL);
306*4afad4b7Schristos 	INSIST(t->nanoseconds < NS_PER_S);
307*4afad4b7Schristos 
308*4afad4b7Schristos 	return ((uint32_t)t->seconds);
309*4afad4b7Schristos }
310*4afad4b7Schristos 
311*4afad4b7Schristos isc_result_t
isc_time_secondsastimet(const isc_time_t * t,time_t * secondsp)312*4afad4b7Schristos isc_time_secondsastimet(const isc_time_t *t, time_t *secondsp) {
313*4afad4b7Schristos 	time_t seconds;
314*4afad4b7Schristos 
315*4afad4b7Schristos 	REQUIRE(t != NULL);
316*4afad4b7Schristos 	INSIST(t->nanoseconds < NS_PER_S);
317*4afad4b7Schristos 
318*4afad4b7Schristos 	/*
319*4afad4b7Schristos 	 * Ensure that the number of seconds represented by t->seconds
320*4afad4b7Schristos 	 * can be represented by a time_t.  Since t->seconds is an
321*4afad4b7Schristos 	 * unsigned int and since time_t is mostly opaque, this is
322*4afad4b7Schristos 	 * trickier than it seems.  (This standardized opaqueness of
323*4afad4b7Schristos 	 * time_t is *very* frustrating; time_t is not even limited to
324*4afad4b7Schristos 	 * being an integral type.)
325*4afad4b7Schristos 	 *
326*4afad4b7Schristos 	 * The mission, then, is to avoid generating any kind of warning
327*4afad4b7Schristos 	 * about "signed versus unsigned" while trying to determine if
328*4afad4b7Schristos 	 * the unsigned int t->seconds is out range for tv_sec,
329*4afad4b7Schristos 	 * which is pretty much only true if time_t is a signed integer
330*4afad4b7Schristos 	 * of the same size as the return value of isc_time_seconds.
331*4afad4b7Schristos 	 *
332*4afad4b7Schristos 	 * If the paradox in the if clause below is true, t->seconds is
333*4afad4b7Schristos 	 * out of range for time_t.
334*4afad4b7Schristos 	 */
335*4afad4b7Schristos 	seconds = (time_t)t->seconds;
336*4afad4b7Schristos 
337*4afad4b7Schristos 	INSIST(sizeof(unsigned int) == sizeof(uint32_t));
338*4afad4b7Schristos 	INSIST(sizeof(time_t) >= sizeof(uint32_t));
339*4afad4b7Schristos 
340*4afad4b7Schristos 	if (t->seconds > (~0U >> 1) && seconds <= (time_t)(~0U >> 1)) {
341*4afad4b7Schristos 		return (ISC_R_RANGE);
342*4afad4b7Schristos 	}
343*4afad4b7Schristos 
344*4afad4b7Schristos 	*secondsp = seconds;
345*4afad4b7Schristos 
346*4afad4b7Schristos 	return (ISC_R_SUCCESS);
347*4afad4b7Schristos }
348*4afad4b7Schristos 
349*4afad4b7Schristos uint32_t
isc_time_nanoseconds(const isc_time_t * t)350*4afad4b7Schristos isc_time_nanoseconds(const isc_time_t *t) {
351*4afad4b7Schristos 	REQUIRE(t != NULL);
352*4afad4b7Schristos 
353*4afad4b7Schristos 	ENSURE(t->nanoseconds < NS_PER_S);
354*4afad4b7Schristos 
355*4afad4b7Schristos 	return ((uint32_t)t->nanoseconds);
356*4afad4b7Schristos }
357*4afad4b7Schristos 
358*4afad4b7Schristos void
isc_time_formattimestamp(const isc_time_t * t,char * buf,unsigned int len)359*4afad4b7Schristos isc_time_formattimestamp(const isc_time_t *t, char *buf, unsigned int len) {
360*4afad4b7Schristos 	time_t now;
361*4afad4b7Schristos 	unsigned int flen;
362*4afad4b7Schristos 	struct tm tm;
363*4afad4b7Schristos 
364*4afad4b7Schristos 	REQUIRE(t != NULL);
365*4afad4b7Schristos 	INSIST(t->nanoseconds < NS_PER_S);
366*4afad4b7Schristos 	REQUIRE(buf != NULL);
367*4afad4b7Schristos 	REQUIRE(len > 0);
368*4afad4b7Schristos 
369*4afad4b7Schristos 	now = (time_t)t->seconds;
370*4afad4b7Schristos 	flen = strftime(buf, len, "%d-%b-%Y %X", localtime_r(&now, &tm));
371*4afad4b7Schristos 	INSIST(flen < len);
372*4afad4b7Schristos 	if (flen != 0) {
373*4afad4b7Schristos 		snprintf(buf + flen, len - flen, ".%03u",
374*4afad4b7Schristos 			 t->nanoseconds / NS_PER_MS);
375*4afad4b7Schristos 	} else {
376*4afad4b7Schristos 		strlcpy(buf, "99-Bad-9999 99:99:99.999", len);
377*4afad4b7Schristos 	}
378*4afad4b7Schristos }
379*4afad4b7Schristos 
380*4afad4b7Schristos void
isc_time_formathttptimestamp(const isc_time_t * t,char * buf,unsigned int len)381*4afad4b7Schristos isc_time_formathttptimestamp(const isc_time_t *t, char *buf, unsigned int len) {
382*4afad4b7Schristos 	time_t now;
383*4afad4b7Schristos 	unsigned int flen;
384*4afad4b7Schristos 	struct tm tm;
385*4afad4b7Schristos 
386*4afad4b7Schristos 	REQUIRE(t != NULL);
387*4afad4b7Schristos 	INSIST(t->nanoseconds < NS_PER_S);
388*4afad4b7Schristos 	REQUIRE(buf != NULL);
389*4afad4b7Schristos 	REQUIRE(len > 0);
390*4afad4b7Schristos 
391*4afad4b7Schristos 	/*
392*4afad4b7Schristos 	 * 5 spaces, 1 comma, 3 GMT, 2 %d, 4 %Y, 8 %H:%M:%S, 3+ %a, 3+
393*4afad4b7Schristos 	 * %b (29+)
394*4afad4b7Schristos 	 */
395*4afad4b7Schristos 	now = (time_t)t->seconds;
396*4afad4b7Schristos 	flen = strftime(buf, len, "%a, %d %b %Y %H:%M:%S GMT",
397*4afad4b7Schristos 			gmtime_r(&now, &tm));
398*4afad4b7Schristos 	INSIST(flen < len);
399*4afad4b7Schristos }
400*4afad4b7Schristos 
401*4afad4b7Schristos isc_result_t
isc_time_parsehttptimestamp(char * buf,isc_time_t * t)402*4afad4b7Schristos isc_time_parsehttptimestamp(char *buf, isc_time_t *t) {
403*4afad4b7Schristos 	struct tm t_tm;
404*4afad4b7Schristos 	time_t when;
405*4afad4b7Schristos 	char *p;
406*4afad4b7Schristos 
407*4afad4b7Schristos 	REQUIRE(buf != NULL);
408*4afad4b7Schristos 	REQUIRE(t != NULL);
409*4afad4b7Schristos 
410*4afad4b7Schristos 	p = isc_tm_strptime(buf, "%a, %d %b %Y %H:%M:%S", &t_tm);
411*4afad4b7Schristos 	if (p == NULL) {
412*4afad4b7Schristos 		return (ISC_R_UNEXPECTED);
413*4afad4b7Schristos 	}
414*4afad4b7Schristos 	when = isc_tm_timegm(&t_tm);
415*4afad4b7Schristos 	if (when == -1) {
416*4afad4b7Schristos 		return (ISC_R_UNEXPECTED);
417*4afad4b7Schristos 	}
418*4afad4b7Schristos 	isc_time_set(t, when, 0);
419*4afad4b7Schristos 	return (ISC_R_SUCCESS);
420*4afad4b7Schristos }
421*4afad4b7Schristos 
422*4afad4b7Schristos void
isc_time_formatISO8601L(const isc_time_t * t,char * buf,unsigned int len)423*4afad4b7Schristos isc_time_formatISO8601L(const isc_time_t *t, char *buf, unsigned int len) {
424*4afad4b7Schristos 	time_t now;
425*4afad4b7Schristos 	unsigned int flen;
426*4afad4b7Schristos 	struct tm tm;
427*4afad4b7Schristos 
428*4afad4b7Schristos 	REQUIRE(t != NULL);
429*4afad4b7Schristos 	INSIST(t->nanoseconds < NS_PER_S);
430*4afad4b7Schristos 	REQUIRE(buf != NULL);
431*4afad4b7Schristos 	REQUIRE(len > 0);
432*4afad4b7Schristos 
433*4afad4b7Schristos 	now = (time_t)t->seconds;
434*4afad4b7Schristos 	flen = strftime(buf, len, "%Y-%m-%dT%H:%M:%S", localtime_r(&now, &tm));
435*4afad4b7Schristos 	INSIST(flen < len);
436*4afad4b7Schristos }
437*4afad4b7Schristos 
438*4afad4b7Schristos void
isc_time_formatISO8601Lms(const isc_time_t * t,char * buf,unsigned int len)439*4afad4b7Schristos isc_time_formatISO8601Lms(const isc_time_t *t, char *buf, unsigned int len) {
440*4afad4b7Schristos 	time_t now;
441*4afad4b7Schristos 	unsigned int flen;
442*4afad4b7Schristos 	struct tm tm;
443*4afad4b7Schristos 
444*4afad4b7Schristos 	REQUIRE(t != NULL);
445*4afad4b7Schristos 	INSIST(t->nanoseconds < NS_PER_S);
446*4afad4b7Schristos 	REQUIRE(buf != NULL);
447*4afad4b7Schristos 	REQUIRE(len > 0);
448*4afad4b7Schristos 
449*4afad4b7Schristos 	now = (time_t)t->seconds;
450*4afad4b7Schristos 	flen = strftime(buf, len, "%Y-%m-%dT%H:%M:%S", localtime_r(&now, &tm));
451*4afad4b7Schristos 	INSIST(flen < len);
452*4afad4b7Schristos 	if (flen > 0U && len - flen >= 6) {
453*4afad4b7Schristos 		snprintf(buf + flen, len - flen, ".%03u",
454*4afad4b7Schristos 			 t->nanoseconds / NS_PER_MS);
455*4afad4b7Schristos 	}
456*4afad4b7Schristos }
457*4afad4b7Schristos 
458*4afad4b7Schristos void
isc_time_formatISO8601Lus(const isc_time_t * t,char * buf,unsigned int len)459*4afad4b7Schristos isc_time_formatISO8601Lus(const isc_time_t *t, char *buf, unsigned int len) {
460*4afad4b7Schristos 	time_t now;
461*4afad4b7Schristos 	unsigned int flen;
462*4afad4b7Schristos 	struct tm tm;
463*4afad4b7Schristos 
464*4afad4b7Schristos 	REQUIRE(t != NULL);
465*4afad4b7Schristos 	INSIST(t->nanoseconds < NS_PER_S);
466*4afad4b7Schristos 	REQUIRE(buf != NULL);
467*4afad4b7Schristos 	REQUIRE(len > 0);
468*4afad4b7Schristos 
469*4afad4b7Schristos 	now = (time_t)t->seconds;
470*4afad4b7Schristos 	flen = strftime(buf, len, "%Y-%m-%dT%H:%M:%S", localtime_r(&now, &tm));
471*4afad4b7Schristos 	INSIST(flen < len);
472*4afad4b7Schristos 	if (flen > 0U && len - flen >= 6) {
473*4afad4b7Schristos 		snprintf(buf + flen, len - flen, ".%06u",
474*4afad4b7Schristos 			 t->nanoseconds / NS_PER_US);
475*4afad4b7Schristos 	}
476*4afad4b7Schristos }
477*4afad4b7Schristos 
478*4afad4b7Schristos void
isc_time_formatISO8601(const isc_time_t * t,char * buf,unsigned int len)479*4afad4b7Schristos isc_time_formatISO8601(const isc_time_t *t, char *buf, unsigned int len) {
480*4afad4b7Schristos 	time_t now;
481*4afad4b7Schristos 	unsigned int flen;
482*4afad4b7Schristos 	struct tm tm;
483*4afad4b7Schristos 
484*4afad4b7Schristos 	REQUIRE(t != NULL);
485*4afad4b7Schristos 	INSIST(t->nanoseconds < NS_PER_S);
486*4afad4b7Schristos 	REQUIRE(buf != NULL);
487*4afad4b7Schristos 	REQUIRE(len > 0);
488*4afad4b7Schristos 
489*4afad4b7Schristos 	now = (time_t)t->seconds;
490*4afad4b7Schristos 	flen = strftime(buf, len, "%Y-%m-%dT%H:%M:%SZ", gmtime_r(&now, &tm));
491*4afad4b7Schristos 	INSIST(flen < len);
492*4afad4b7Schristos }
493*4afad4b7Schristos 
494*4afad4b7Schristos void
isc_time_formatISO8601ms(const isc_time_t * t,char * buf,unsigned int len)495*4afad4b7Schristos isc_time_formatISO8601ms(const isc_time_t *t, char *buf, unsigned int len) {
496*4afad4b7Schristos 	time_t now;
497*4afad4b7Schristos 	unsigned int flen;
498*4afad4b7Schristos 	struct tm tm;
499*4afad4b7Schristos 
500*4afad4b7Schristos 	REQUIRE(t != NULL);
501*4afad4b7Schristos 	INSIST(t->nanoseconds < NS_PER_S);
502*4afad4b7Schristos 	REQUIRE(buf != NULL);
503*4afad4b7Schristos 	REQUIRE(len > 0);
504*4afad4b7Schristos 
505*4afad4b7Schristos 	now = (time_t)t->seconds;
506*4afad4b7Schristos 	flen = strftime(buf, len, "%Y-%m-%dT%H:%M:%SZ", gmtime_r(&now, &tm));
507*4afad4b7Schristos 	INSIST(flen < len);
508*4afad4b7Schristos 	if (flen > 0U && len - flen >= 5) {
509*4afad4b7Schristos 		flen -= 1; /* rewind one character (Z) */
510*4afad4b7Schristos 		snprintf(buf + flen, len - flen, ".%03uZ",
511*4afad4b7Schristos 			 t->nanoseconds / NS_PER_MS);
512*4afad4b7Schristos 	}
513*4afad4b7Schristos }
514*4afad4b7Schristos 
515*4afad4b7Schristos void
isc_time_formatISO8601us(const isc_time_t * t,char * buf,unsigned int len)516*4afad4b7Schristos isc_time_formatISO8601us(const isc_time_t *t, char *buf, unsigned int len) {
517*4afad4b7Schristos 	time_t now;
518*4afad4b7Schristos 	unsigned int flen;
519*4afad4b7Schristos 	struct tm tm;
520*4afad4b7Schristos 
521*4afad4b7Schristos 	REQUIRE(t != NULL);
522*4afad4b7Schristos 	INSIST(t->nanoseconds < NS_PER_S);
523*4afad4b7Schristos 	REQUIRE(buf != NULL);
524*4afad4b7Schristos 	REQUIRE(len > 0);
525*4afad4b7Schristos 
526*4afad4b7Schristos 	now = (time_t)t->seconds;
527*4afad4b7Schristos 	flen = strftime(buf, len, "%Y-%m-%dT%H:%M:%SZ", gmtime_r(&now, &tm));
528*4afad4b7Schristos 	INSIST(flen < len);
529*4afad4b7Schristos 	if (flen > 0U && len - flen >= 5) {
530*4afad4b7Schristos 		flen -= 1; /* rewind one character (Z) */
531*4afad4b7Schristos 		snprintf(buf + flen, len - flen, ".%06uZ",
532*4afad4b7Schristos 			 t->nanoseconds / NS_PER_US);
533*4afad4b7Schristos 	}
534*4afad4b7Schristos }
535*4afad4b7Schristos 
536*4afad4b7Schristos void
isc_time_formatshorttimestamp(const isc_time_t * t,char * buf,unsigned int len)537*4afad4b7Schristos isc_time_formatshorttimestamp(const isc_time_t *t, char *buf,
538*4afad4b7Schristos 			      unsigned int len) {
539*4afad4b7Schristos 	time_t now;
540*4afad4b7Schristos 	unsigned int flen;
541*4afad4b7Schristos 	struct tm tm;
542*4afad4b7Schristos 
543*4afad4b7Schristos 	REQUIRE(t != NULL);
544*4afad4b7Schristos 	INSIST(t->nanoseconds < NS_PER_S);
545*4afad4b7Schristos 	REQUIRE(buf != NULL);
546*4afad4b7Schristos 	REQUIRE(len > 0);
547*4afad4b7Schristos 
548*4afad4b7Schristos 	now = (time_t)t->seconds;
549*4afad4b7Schristos 	flen = strftime(buf, len, "%Y%m%d%H%M%S", gmtime_r(&now, &tm));
550*4afad4b7Schristos 	INSIST(flen < len);
551*4afad4b7Schristos 	if (flen > 0U && len - flen >= 5) {
552*4afad4b7Schristos 		snprintf(buf + flen, len - flen, "%03u",
553*4afad4b7Schristos 			 t->nanoseconds / NS_PER_MS);
554*4afad4b7Schristos 	}
555*4afad4b7Schristos }
556