xref: /netbsd-src/external/bsd/ntp/dist/libntp/lib/isc/unix/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-2008, 2011, 2012  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 */
21897be3a4Schristos 
22897be3a4Schristos /*! \file */
23897be3a4Schristos 
24897be3a4Schristos #include <config.h>
25897be3a4Schristos 
26897be3a4Schristos #include <errno.h>
27897be3a4Schristos #include <limits.h>
28897be3a4Schristos #include <syslog.h>
29897be3a4Schristos #include <time.h>
30897be3a4Schristos 
31897be3a4Schristos #include <sys/time.h>	/* Required for struct timeval on some platforms. */
32897be3a4Schristos 
33897be3a4Schristos #include <isc/log.h>
34897be3a4Schristos #include <isc/print.h>
35897be3a4Schristos #include <isc/strerror.h>
36897be3a4Schristos #include <isc/string.h>
37897be3a4Schristos #include <isc/time.h>
38897be3a4Schristos #include <isc/util.h>
39897be3a4Schristos 
40897be3a4Schristos #define NS_PER_S	1000000000	/*%< Nanoseconds per second. */
41897be3a4Schristos #define NS_PER_US	1000		/*%< Nanoseconds per microsecond. */
42897be3a4Schristos #define US_PER_S	1000000		/*%< Microseconds per second. */
43897be3a4Schristos 
44897be3a4Schristos /*
45897be3a4Schristos  * All of the INSIST()s checks of nanoseconds < NS_PER_S are for
46897be3a4Schristos  * consistency checking of the type. In lieu of magic numbers, it
47897be3a4Schristos  * is the best we've got.  The check is only performed on functions which
48897be3a4Schristos  * need an initialized type.
49897be3a4Schristos  */
50897be3a4Schristos 
51897be3a4Schristos #ifndef ISC_FIX_TV_USEC
52897be3a4Schristos #define ISC_FIX_TV_USEC 1
53897be3a4Schristos #endif
54897be3a4Schristos 
55897be3a4Schristos /*%
56897be3a4Schristos  *** Intervals
57897be3a4Schristos  ***/
58897be3a4Schristos 
59897be3a4Schristos static isc_interval_t zero_interval = { 0, 0 };
60897be3a4Schristos isc_interval_t *isc_interval_zero = &zero_interval;
61897be3a4Schristos 
62897be3a4Schristos #if ISC_FIX_TV_USEC
63897be3a4Schristos static inline void
64897be3a4Schristos fix_tv_usec(struct timeval *tv) {
65897be3a4Schristos 	isc_boolean_t fixed = ISC_FALSE;
66897be3a4Schristos 
67897be3a4Schristos 	if (tv->tv_usec < 0) {
68897be3a4Schristos 		fixed = ISC_TRUE;
69897be3a4Schristos 		do {
70897be3a4Schristos 			tv->tv_sec -= 1;
71897be3a4Schristos 			tv->tv_usec += US_PER_S;
72897be3a4Schristos 		} while (tv->tv_usec < 0);
73897be3a4Schristos 	} else if (tv->tv_usec >= US_PER_S) {
74897be3a4Schristos 		fixed = ISC_TRUE;
75897be3a4Schristos 		do {
76897be3a4Schristos 			tv->tv_sec += 1;
77897be3a4Schristos 			tv->tv_usec -= US_PER_S;
78897be3a4Schristos 		} while (tv->tv_usec >=US_PER_S);
79897be3a4Schristos 	}
80897be3a4Schristos 	/*
81897be3a4Schristos 	 * Call syslog directly as was are called from the logging functions.
82897be3a4Schristos 	 */
83897be3a4Schristos 	if (fixed)
84897be3a4Schristos 		(void)syslog(LOG_ERR, "gettimeofday returned bad tv_usec: corrected");
85897be3a4Schristos }
86897be3a4Schristos #endif
87897be3a4Schristos 
88897be3a4Schristos void
89897be3a4Schristos isc_interval_set(isc_interval_t *i,
90897be3a4Schristos 		 unsigned int seconds, unsigned int nanoseconds)
91897be3a4Schristos {
92897be3a4Schristos 	REQUIRE(i != NULL);
93897be3a4Schristos 	REQUIRE(nanoseconds < NS_PER_S);
94897be3a4Schristos 
95897be3a4Schristos 	i->seconds = seconds;
96897be3a4Schristos 	i->nanoseconds = nanoseconds;
97897be3a4Schristos }
98897be3a4Schristos 
99897be3a4Schristos isc_boolean_t
100897be3a4Schristos isc_interval_iszero(const isc_interval_t *i) {
101897be3a4Schristos 	REQUIRE(i != NULL);
102897be3a4Schristos 	INSIST(i->nanoseconds < NS_PER_S);
103897be3a4Schristos 
104897be3a4Schristos 	if (i->seconds == 0 && i->nanoseconds == 0)
105897be3a4Schristos 		return (ISC_TRUE);
106897be3a4Schristos 
107897be3a4Schristos 	return (ISC_FALSE);
108897be3a4Schristos }
109897be3a4Schristos 
110897be3a4Schristos 
111897be3a4Schristos /***
112897be3a4Schristos  *** Absolute Times
113897be3a4Schristos  ***/
114897be3a4Schristos 
115897be3a4Schristos static isc_time_t epoch = { 0, 0 };
116897be3a4Schristos isc_time_t *isc_time_epoch = &epoch;
117897be3a4Schristos 
118897be3a4Schristos void
119897be3a4Schristos isc_time_set(isc_time_t *t, unsigned int seconds, unsigned int nanoseconds) {
120897be3a4Schristos 	REQUIRE(t != NULL);
121897be3a4Schristos 	REQUIRE(nanoseconds < NS_PER_S);
122897be3a4Schristos 
123897be3a4Schristos 	t->seconds = seconds;
124897be3a4Schristos 	t->nanoseconds = nanoseconds;
125897be3a4Schristos }
126897be3a4Schristos 
127897be3a4Schristos void
128897be3a4Schristos isc_time_settoepoch(isc_time_t *t) {
129897be3a4Schristos 	REQUIRE(t != NULL);
130897be3a4Schristos 
131897be3a4Schristos 	t->seconds = 0;
132897be3a4Schristos 	t->nanoseconds = 0;
133897be3a4Schristos }
134897be3a4Schristos 
135897be3a4Schristos isc_boolean_t
136897be3a4Schristos isc_time_isepoch(const isc_time_t *t) {
137897be3a4Schristos 	REQUIRE(t != NULL);
138897be3a4Schristos 	INSIST(t->nanoseconds < NS_PER_S);
139897be3a4Schristos 
140897be3a4Schristos 	if (t->seconds == 0 && t->nanoseconds == 0)
141897be3a4Schristos 		return (ISC_TRUE);
142897be3a4Schristos 
143897be3a4Schristos 	return (ISC_FALSE);
144897be3a4Schristos }
145897be3a4Schristos 
146897be3a4Schristos 
147897be3a4Schristos isc_result_t
148897be3a4Schristos isc_time_now(isc_time_t *t) {
149897be3a4Schristos 	struct timeval tv;
150897be3a4Schristos 	char strbuf[ISC_STRERRORSIZE];
151897be3a4Schristos 
152897be3a4Schristos 	REQUIRE(t != NULL);
153897be3a4Schristos 
154897be3a4Schristos 	if (gettimeofday(&tv, NULL) == -1) {
155897be3a4Schristos 		isc__strerror(errno, strbuf, sizeof(strbuf));
156897be3a4Schristos 		UNEXPECTED_ERROR(__FILE__, __LINE__, "%s", strbuf);
157897be3a4Schristos 		return (ISC_R_UNEXPECTED);
158897be3a4Schristos 	}
159897be3a4Schristos 
160897be3a4Schristos 	/*
161897be3a4Schristos 	 * Does POSIX guarantee the signedness of tv_sec and tv_usec?  If not,
162897be3a4Schristos 	 * then this test will generate warnings for platforms on which it is
163897be3a4Schristos 	 * unsigned.  In any event, the chances of any of these problems
164897be3a4Schristos 	 * happening are pretty much zero, but since the libisc library ensures
165897be3a4Schristos 	 * certain things to be true ...
166897be3a4Schristos 	 */
167897be3a4Schristos #if ISC_FIX_TV_USEC
168897be3a4Schristos 	fix_tv_usec(&tv);
169897be3a4Schristos 	if (tv.tv_sec < 0)
170897be3a4Schristos 		return (ISC_R_UNEXPECTED);
171897be3a4Schristos #else
172897be3a4Schristos 	if (tv.tv_sec < 0 || tv.tv_usec < 0 || tv.tv_usec >= US_PER_S)
173897be3a4Schristos 		return (ISC_R_UNEXPECTED);
174897be3a4Schristos #endif
175897be3a4Schristos 
176897be3a4Schristos 	/*
177897be3a4Schristos 	 * Ensure the tv_sec value fits in t->seconds.
178897be3a4Schristos 	 */
179897be3a4Schristos 	if (sizeof(tv.tv_sec) > sizeof(t->seconds) &&
180897be3a4Schristos 	    ((tv.tv_sec | (unsigned int)-1) ^ (unsigned int)-1) != 0U)
181897be3a4Schristos 		return (ISC_R_RANGE);
182897be3a4Schristos 
183897be3a4Schristos 	t->seconds = tv.tv_sec;
184897be3a4Schristos 	t->nanoseconds = tv.tv_usec * NS_PER_US;
185897be3a4Schristos 
186897be3a4Schristos 	return (ISC_R_SUCCESS);
187897be3a4Schristos }
188897be3a4Schristos 
189897be3a4Schristos isc_result_t
190897be3a4Schristos isc_time_nowplusinterval(isc_time_t *t, const isc_interval_t *i) {
191897be3a4Schristos 	struct timeval tv;
192897be3a4Schristos 	char strbuf[ISC_STRERRORSIZE];
193897be3a4Schristos 
194897be3a4Schristos 	REQUIRE(t != NULL);
195897be3a4Schristos 	REQUIRE(i != NULL);
196897be3a4Schristos 	INSIST(i->nanoseconds < NS_PER_S);
197897be3a4Schristos 
198897be3a4Schristos 	if (gettimeofday(&tv, NULL) == -1) {
199897be3a4Schristos 		isc__strerror(errno, strbuf, sizeof(strbuf));
200897be3a4Schristos 		UNEXPECTED_ERROR(__FILE__, __LINE__, "%s", strbuf);
201897be3a4Schristos 		return (ISC_R_UNEXPECTED);
202897be3a4Schristos 	}
203897be3a4Schristos 
204897be3a4Schristos 	/*
205897be3a4Schristos 	 * Does POSIX guarantee the signedness of tv_sec and tv_usec?  If not,
206897be3a4Schristos 	 * then this test will generate warnings for platforms on which it is
207897be3a4Schristos 	 * unsigned.  In any event, the chances of any of these problems
208897be3a4Schristos 	 * happening are pretty much zero, but since the libisc library ensures
209897be3a4Schristos 	 * certain things to be true ...
210897be3a4Schristos 	 */
211897be3a4Schristos #if ISC_FIX_TV_USEC
212897be3a4Schristos 	fix_tv_usec(&tv);
213897be3a4Schristos 	if (tv.tv_sec < 0)
214897be3a4Schristos 		return (ISC_R_UNEXPECTED);
215897be3a4Schristos #else
216897be3a4Schristos 	if (tv.tv_sec < 0 || tv.tv_usec < 0 || tv.tv_usec >= US_PER_S)
217897be3a4Schristos 		return (ISC_R_UNEXPECTED);
218897be3a4Schristos #endif
219897be3a4Schristos 
220897be3a4Schristos 	/*
221897be3a4Schristos 	 * Ensure the resulting seconds value fits in the size of an
222897be3a4Schristos 	 * unsigned int.  (It is written this way as a slight optimization;
223897be3a4Schristos 	 * note that even if both values == INT_MAX, then when added
224897be3a4Schristos 	 * and getting another 1 added below the result is UINT_MAX.)
225897be3a4Schristos 	 */
226897be3a4Schristos 	if ((tv.tv_sec > INT_MAX || i->seconds > INT_MAX) &&
227897be3a4Schristos 	    ((long long)tv.tv_sec + i->seconds > UINT_MAX))
228897be3a4Schristos 		return (ISC_R_RANGE);
229897be3a4Schristos 
230897be3a4Schristos 	t->seconds = tv.tv_sec + i->seconds;
231897be3a4Schristos 	t->nanoseconds = tv.tv_usec * NS_PER_US + i->nanoseconds;
232897be3a4Schristos 	if (t->nanoseconds >= NS_PER_S) {
233897be3a4Schristos 		t->seconds++;
234897be3a4Schristos 		t->nanoseconds -= NS_PER_S;
235897be3a4Schristos 	}
236897be3a4Schristos 
237897be3a4Schristos 	return (ISC_R_SUCCESS);
238897be3a4Schristos }
239897be3a4Schristos 
240897be3a4Schristos int
241897be3a4Schristos isc_time_compare(const isc_time_t *t1, const isc_time_t *t2) {
242897be3a4Schristos 	REQUIRE(t1 != NULL && t2 != NULL);
243897be3a4Schristos 	INSIST(t1->nanoseconds < NS_PER_S && t2->nanoseconds < NS_PER_S);
244897be3a4Schristos 
245897be3a4Schristos 	if (t1->seconds < t2->seconds)
246897be3a4Schristos 		return (-1);
247897be3a4Schristos 	if (t1->seconds > t2->seconds)
248897be3a4Schristos 		return (1);
249897be3a4Schristos 	if (t1->nanoseconds < t2->nanoseconds)
250897be3a4Schristos 		return (-1);
251897be3a4Schristos 	if (t1->nanoseconds > t2->nanoseconds)
252897be3a4Schristos 		return (1);
253897be3a4Schristos 	return (0);
254897be3a4Schristos }
255897be3a4Schristos 
256897be3a4Schristos isc_result_t
257897be3a4Schristos isc_time_add(const isc_time_t *t, const isc_interval_t *i, isc_time_t *result)
258897be3a4Schristos {
259897be3a4Schristos 	REQUIRE(t != NULL && i != NULL && result != NULL);
260897be3a4Schristos 	INSIST(t->nanoseconds < NS_PER_S && i->nanoseconds < NS_PER_S);
261897be3a4Schristos 
262897be3a4Schristos 	/*
263897be3a4Schristos 	 * Ensure the resulting seconds value fits in the size of an
264897be3a4Schristos 	 * unsigned int.  (It is written this way as a slight optimization;
265897be3a4Schristos 	 * note that even if both values == INT_MAX, then when added
266897be3a4Schristos 	 * and getting another 1 added below the result is UINT_MAX.)
267897be3a4Schristos 	 */
268897be3a4Schristos 	if ((t->seconds > INT_MAX || i->seconds > INT_MAX) &&
269897be3a4Schristos 	    ((long long)t->seconds + i->seconds > UINT_MAX))
270897be3a4Schristos 		return (ISC_R_RANGE);
271897be3a4Schristos 
272897be3a4Schristos 	result->seconds = t->seconds + i->seconds;
273897be3a4Schristos 	result->nanoseconds = t->nanoseconds + i->nanoseconds;
274897be3a4Schristos 	if (result->nanoseconds >= NS_PER_S) {
275897be3a4Schristos 		result->seconds++;
276897be3a4Schristos 		result->nanoseconds -= NS_PER_S;
277897be3a4Schristos 	}
278897be3a4Schristos 
279897be3a4Schristos 	return (ISC_R_SUCCESS);
280897be3a4Schristos }
281897be3a4Schristos 
282897be3a4Schristos isc_result_t
283897be3a4Schristos isc_time_subtract(const isc_time_t *t, const isc_interval_t *i,
284897be3a4Schristos 		  isc_time_t *result)
285897be3a4Schristos {
286897be3a4Schristos 	REQUIRE(t != NULL && i != NULL && result != NULL);
287897be3a4Schristos 	INSIST(t->nanoseconds < NS_PER_S && i->nanoseconds < NS_PER_S);
288897be3a4Schristos 
289897be3a4Schristos 	if ((unsigned int)t->seconds < i->seconds ||
290897be3a4Schristos 	    ((unsigned int)t->seconds == i->seconds &&
291897be3a4Schristos 	     t->nanoseconds < i->nanoseconds))
292897be3a4Schristos 	    return (ISC_R_RANGE);
293897be3a4Schristos 
294897be3a4Schristos 	result->seconds = t->seconds - i->seconds;
295897be3a4Schristos 	if (t->nanoseconds >= i->nanoseconds)
296897be3a4Schristos 		result->nanoseconds = t->nanoseconds - i->nanoseconds;
297897be3a4Schristos 	else {
298897be3a4Schristos 		result->nanoseconds = NS_PER_S - i->nanoseconds +
299897be3a4Schristos 			t->nanoseconds;
300897be3a4Schristos 		result->seconds--;
301897be3a4Schristos 	}
302897be3a4Schristos 
303897be3a4Schristos 	return (ISC_R_SUCCESS);
304897be3a4Schristos }
305897be3a4Schristos 
306897be3a4Schristos isc_uint64_t
307897be3a4Schristos isc_time_microdiff(const isc_time_t *t1, const isc_time_t *t2) {
308897be3a4Schristos 	isc_uint64_t i1, i2, i3;
309897be3a4Schristos 
310897be3a4Schristos 	REQUIRE(t1 != NULL && t2 != NULL);
311897be3a4Schristos 	INSIST(t1->nanoseconds < NS_PER_S && t2->nanoseconds < NS_PER_S);
312897be3a4Schristos 
313897be3a4Schristos 	i1 = (isc_uint64_t)t1->seconds * NS_PER_S + t1->nanoseconds;
314897be3a4Schristos 	i2 = (isc_uint64_t)t2->seconds * NS_PER_S + t2->nanoseconds;
315897be3a4Schristos 
316897be3a4Schristos 	if (i1 <= i2)
317897be3a4Schristos 		return (0);
318897be3a4Schristos 
319897be3a4Schristos 	i3 = i1 - i2;
320897be3a4Schristos 
321897be3a4Schristos 	/*
322897be3a4Schristos 	 * Convert to microseconds.
323897be3a4Schristos 	 */
324897be3a4Schristos 	i3 /= NS_PER_US;
325897be3a4Schristos 
326897be3a4Schristos 	return (i3);
327897be3a4Schristos }
328897be3a4Schristos 
329897be3a4Schristos isc_uint32_t
330897be3a4Schristos isc_time_seconds(const isc_time_t *t) {
331897be3a4Schristos 	REQUIRE(t != NULL);
332897be3a4Schristos 	INSIST(t->nanoseconds < NS_PER_S);
333897be3a4Schristos 
334897be3a4Schristos 	return ((isc_uint32_t)t->seconds);
335897be3a4Schristos }
336897be3a4Schristos 
337897be3a4Schristos isc_result_t
338897be3a4Schristos isc_time_secondsastimet(const isc_time_t *t, time_t *secondsp) {
339897be3a4Schristos 	time_t seconds;
340897be3a4Schristos 
341897be3a4Schristos 	REQUIRE(t != NULL);
342897be3a4Schristos 	INSIST(t->nanoseconds < NS_PER_S);
343897be3a4Schristos 
344897be3a4Schristos 	/*
345897be3a4Schristos 	 * Ensure that the number of seconds represented by t->seconds
346897be3a4Schristos 	 * can be represented by a time_t.  Since t->seconds is an unsigned
347897be3a4Schristos 	 * int and since time_t is mostly opaque, this is trickier than
348897be3a4Schristos 	 * it seems.  (This standardized opaqueness of time_t is *very*
349897be3a4Schristos 	 * frustrating; time_t is not even limited to being an integral
350897be3a4Schristos 	 * type.)
351897be3a4Schristos 	 *
352897be3a4Schristos 	 * The mission, then, is to avoid generating any kind of warning
353897be3a4Schristos 	 * about "signed versus unsigned" while trying to determine if the
354897be3a4Schristos 	 * the unsigned int t->seconds is out range for tv_sec, which is
355897be3a4Schristos 	 * pretty much only true if time_t is a signed integer of the same
356897be3a4Schristos 	 * size as the return value of isc_time_seconds.
357897be3a4Schristos 	 *
358897be3a4Schristos 	 * If the paradox in the if clause below is true, t->seconds is out
359897be3a4Schristos 	 * of range for time_t.
360897be3a4Schristos 	 */
361897be3a4Schristos 	seconds = (time_t)t->seconds;
362897be3a4Schristos 
363897be3a4Schristos 	INSIST(sizeof(unsigned int) == sizeof(isc_uint32_t));
364897be3a4Schristos 	INSIST(sizeof(time_t) >= sizeof(isc_uint32_t));
365897be3a4Schristos 
366897be3a4Schristos 	if (t->seconds > (~0U>>1) && seconds <= (time_t)(~0U>>1))
367897be3a4Schristos 		return (ISC_R_RANGE);
368897be3a4Schristos 
369897be3a4Schristos 	*secondsp = seconds;
370897be3a4Schristos 
371897be3a4Schristos 	return (ISC_R_SUCCESS);
372897be3a4Schristos }
373897be3a4Schristos 
374897be3a4Schristos isc_uint32_t
375897be3a4Schristos isc_time_nanoseconds(const isc_time_t *t) {
376897be3a4Schristos 	REQUIRE(t != NULL);
377897be3a4Schristos 
378897be3a4Schristos 	ENSURE(t->nanoseconds < NS_PER_S);
379897be3a4Schristos 
380897be3a4Schristos 	return ((isc_uint32_t)t->nanoseconds);
381897be3a4Schristos }
382897be3a4Schristos 
383897be3a4Schristos void
384897be3a4Schristos isc_time_formattimestamp(const isc_time_t *t, char *buf, unsigned int len) {
385897be3a4Schristos 	time_t now;
386897be3a4Schristos 	unsigned int flen;
387897be3a4Schristos 
388897be3a4Schristos 	REQUIRE(len > 0);
389897be3a4Schristos 
390897be3a4Schristos 	now = (time_t) t->seconds;
391897be3a4Schristos 	flen = strftime(buf, len, "%d-%b-%Y %X", localtime(&now));
392897be3a4Schristos 	INSIST(flen < len);
393897be3a4Schristos 	if (flen != 0)
394897be3a4Schristos 		snprintf(buf + flen, len - flen,
395897be3a4Schristos 			 ".%03u", t->nanoseconds / 1000000);
396897be3a4Schristos 	else
397897be3a4Schristos 		snprintf(buf, len, "99-Bad-9999 99:99:99.999");
398897be3a4Schristos }
399897be3a4Schristos 
400897be3a4Schristos void
401897be3a4Schristos isc_time_formathttptimestamp(const isc_time_t *t, char *buf, unsigned int len) {
402897be3a4Schristos 	time_t now;
403897be3a4Schristos 	unsigned int flen;
404897be3a4Schristos 
405897be3a4Schristos 	REQUIRE(len > 0);
406897be3a4Schristos 
407897be3a4Schristos 	now = (time_t)t->seconds;
408897be3a4Schristos 	flen = strftime(buf, len, "%a, %d %b %Y %H:%M:%S GMT", gmtime(&now));
409897be3a4Schristos 	INSIST(flen < len);
410897be3a4Schristos }
411897be3a4Schristos 
412897be3a4Schristos void
413897be3a4Schristos isc_time_formatISO8601(const isc_time_t *t, char *buf, unsigned int len) {
414897be3a4Schristos 	time_t now;
415897be3a4Schristos 	unsigned int flen;
416897be3a4Schristos 
417897be3a4Schristos 	REQUIRE(len > 0);
418897be3a4Schristos 
419897be3a4Schristos 	now = (time_t)t->seconds;
420897be3a4Schristos 	flen = strftime(buf, len, "%Y-%m-%dT%H:%M:%SZ", gmtime(&now));
421897be3a4Schristos 	INSIST(flen < len);
422897be3a4Schristos }
423