xref: /minix/external/bsd/bind/dist/lib/isc/unix/time.c (revision 00b67f09)
1*00b67f09SDavid van Moolenbroek /*	$NetBSD: time.c,v 1.9 2015/07/08 17:29:00 christos Exp $	*/
2*00b67f09SDavid van Moolenbroek 
3*00b67f09SDavid van Moolenbroek /*
4*00b67f09SDavid van Moolenbroek  * Copyright (C) 2004-2008, 2011, 2012, 2014, 2015  Internet Systems Consortium, Inc. ("ISC")
5*00b67f09SDavid van Moolenbroek  * Copyright (C) 1998-2001, 2003  Internet Software Consortium.
6*00b67f09SDavid van Moolenbroek  *
7*00b67f09SDavid van Moolenbroek  * Permission to use, copy, modify, and/or distribute this software for any
8*00b67f09SDavid van Moolenbroek  * purpose with or without fee is hereby granted, provided that the above
9*00b67f09SDavid van Moolenbroek  * copyright notice and this permission notice appear in all copies.
10*00b67f09SDavid van Moolenbroek  *
11*00b67f09SDavid van Moolenbroek  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12*00b67f09SDavid van Moolenbroek  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13*00b67f09SDavid van Moolenbroek  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14*00b67f09SDavid van Moolenbroek  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15*00b67f09SDavid van Moolenbroek  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16*00b67f09SDavid van Moolenbroek  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17*00b67f09SDavid van Moolenbroek  * PERFORMANCE OF THIS SOFTWARE.
18*00b67f09SDavid van Moolenbroek  */
19*00b67f09SDavid van Moolenbroek 
20*00b67f09SDavid van Moolenbroek /* Id */
21*00b67f09SDavid van Moolenbroek 
22*00b67f09SDavid van Moolenbroek /*! \file */
23*00b67f09SDavid van Moolenbroek 
24*00b67f09SDavid van Moolenbroek #include <config.h>
25*00b67f09SDavid van Moolenbroek 
26*00b67f09SDavid van Moolenbroek #include <errno.h>
27*00b67f09SDavid van Moolenbroek #include <limits.h>
28*00b67f09SDavid van Moolenbroek #include <stdlib.h>
29*00b67f09SDavid van Moolenbroek #include <syslog.h>
30*00b67f09SDavid van Moolenbroek #include <time.h>
31*00b67f09SDavid van Moolenbroek 
32*00b67f09SDavid van Moolenbroek #include <sys/time.h>	/* Required for struct timeval on some platforms. */
33*00b67f09SDavid van Moolenbroek 
34*00b67f09SDavid van Moolenbroek #include <isc/log.h>
35*00b67f09SDavid van Moolenbroek #include <isc/print.h>
36*00b67f09SDavid van Moolenbroek #include <isc/strerror.h>
37*00b67f09SDavid van Moolenbroek #include <isc/string.h>
38*00b67f09SDavid van Moolenbroek #include <isc/time.h>
39*00b67f09SDavid van Moolenbroek #include <isc/tm.h>
40*00b67f09SDavid van Moolenbroek #include <isc/util.h>
41*00b67f09SDavid van Moolenbroek 
42*00b67f09SDavid van Moolenbroek #define NS_PER_S	1000000000	/*%< Nanoseconds per second. */
43*00b67f09SDavid van Moolenbroek #define NS_PER_US	1000		/*%< Nanoseconds per microsecond. */
44*00b67f09SDavid van Moolenbroek #define US_PER_S	1000000		/*%< Microseconds per second. */
45*00b67f09SDavid van Moolenbroek 
46*00b67f09SDavid van Moolenbroek /*
47*00b67f09SDavid van Moolenbroek  * All of the INSIST()s checks of nanoseconds < NS_PER_S are for
48*00b67f09SDavid van Moolenbroek  * consistency checking of the type. In lieu of magic numbers, it
49*00b67f09SDavid van Moolenbroek  * is the best we've got.  The check is only performed on functions which
50*00b67f09SDavid van Moolenbroek  * need an initialized type.
51*00b67f09SDavid van Moolenbroek  */
52*00b67f09SDavid van Moolenbroek 
53*00b67f09SDavid van Moolenbroek #ifndef ISC_FIX_TV_USEC
54*00b67f09SDavid van Moolenbroek #define ISC_FIX_TV_USEC 1
55*00b67f09SDavid van Moolenbroek #endif
56*00b67f09SDavid van Moolenbroek 
57*00b67f09SDavid van Moolenbroek /*%
58*00b67f09SDavid van Moolenbroek  *** Intervals
59*00b67f09SDavid van Moolenbroek  ***/
60*00b67f09SDavid van Moolenbroek 
61*00b67f09SDavid van Moolenbroek static const isc_interval_t zero_interval = { 0, 0 };
62*00b67f09SDavid van Moolenbroek const isc_interval_t * const isc_interval_zero = &zero_interval;
63*00b67f09SDavid van Moolenbroek 
64*00b67f09SDavid van Moolenbroek #if ISC_FIX_TV_USEC
65*00b67f09SDavid van Moolenbroek static inline void
fix_tv_usec(struct timeval * tv)66*00b67f09SDavid van Moolenbroek fix_tv_usec(struct timeval *tv) {
67*00b67f09SDavid van Moolenbroek 	isc_boolean_t fixed = ISC_FALSE;
68*00b67f09SDavid van Moolenbroek 
69*00b67f09SDavid van Moolenbroek 	if (tv->tv_usec < 0) {
70*00b67f09SDavid van Moolenbroek 		fixed = ISC_TRUE;
71*00b67f09SDavid van Moolenbroek 		do {
72*00b67f09SDavid van Moolenbroek 			tv->tv_sec -= 1;
73*00b67f09SDavid van Moolenbroek 			tv->tv_usec += US_PER_S;
74*00b67f09SDavid van Moolenbroek 		} while (tv->tv_usec < 0);
75*00b67f09SDavid van Moolenbroek 	} else if (tv->tv_usec >= US_PER_S) {
76*00b67f09SDavid van Moolenbroek 		fixed = ISC_TRUE;
77*00b67f09SDavid van Moolenbroek 		do {
78*00b67f09SDavid van Moolenbroek 			tv->tv_sec += 1;
79*00b67f09SDavid van Moolenbroek 			tv->tv_usec -= US_PER_S;
80*00b67f09SDavid van Moolenbroek 		} while (tv->tv_usec >=US_PER_S);
81*00b67f09SDavid van Moolenbroek 	}
82*00b67f09SDavid van Moolenbroek 	/*
83*00b67f09SDavid van Moolenbroek 	 * Call syslog directly as was are called from the logging functions.
84*00b67f09SDavid van Moolenbroek 	 */
85*00b67f09SDavid van Moolenbroek 	if (fixed)
86*00b67f09SDavid van Moolenbroek 		(void)syslog(LOG_ERR, "gettimeofday returned bad tv_usec: corrected");
87*00b67f09SDavid van Moolenbroek }
88*00b67f09SDavid van Moolenbroek #endif
89*00b67f09SDavid van Moolenbroek 
90*00b67f09SDavid van Moolenbroek void
isc_interval_set(isc_interval_t * i,unsigned int seconds,unsigned int nanoseconds)91*00b67f09SDavid van Moolenbroek isc_interval_set(isc_interval_t *i,
92*00b67f09SDavid van Moolenbroek 		 unsigned int seconds, unsigned int nanoseconds)
93*00b67f09SDavid van Moolenbroek {
94*00b67f09SDavid van Moolenbroek 	REQUIRE(i != NULL);
95*00b67f09SDavid van Moolenbroek 	REQUIRE(nanoseconds < NS_PER_S);
96*00b67f09SDavid van Moolenbroek 
97*00b67f09SDavid van Moolenbroek 	i->seconds = seconds;
98*00b67f09SDavid van Moolenbroek 	i->nanoseconds = nanoseconds;
99*00b67f09SDavid van Moolenbroek }
100*00b67f09SDavid van Moolenbroek 
101*00b67f09SDavid van Moolenbroek isc_boolean_t
isc_interval_iszero(const isc_interval_t * i)102*00b67f09SDavid van Moolenbroek isc_interval_iszero(const isc_interval_t *i) {
103*00b67f09SDavid van Moolenbroek 	REQUIRE(i != NULL);
104*00b67f09SDavid van Moolenbroek 	INSIST(i->nanoseconds < NS_PER_S);
105*00b67f09SDavid van Moolenbroek 
106*00b67f09SDavid van Moolenbroek 	if (i->seconds == 0 && i->nanoseconds == 0)
107*00b67f09SDavid van Moolenbroek 		return (ISC_TRUE);
108*00b67f09SDavid van Moolenbroek 
109*00b67f09SDavid van Moolenbroek 	return (ISC_FALSE);
110*00b67f09SDavid van Moolenbroek }
111*00b67f09SDavid van Moolenbroek 
112*00b67f09SDavid van Moolenbroek 
113*00b67f09SDavid van Moolenbroek /***
114*00b67f09SDavid van Moolenbroek  *** Absolute Times
115*00b67f09SDavid van Moolenbroek  ***/
116*00b67f09SDavid van Moolenbroek 
117*00b67f09SDavid van Moolenbroek static const isc_time_t epoch = { 0, 0 };
118*00b67f09SDavid van Moolenbroek const isc_time_t * const isc_time_epoch = &epoch;
119*00b67f09SDavid van Moolenbroek 
120*00b67f09SDavid van Moolenbroek void
isc_time_set(isc_time_t * t,unsigned int seconds,unsigned int nanoseconds)121*00b67f09SDavid van Moolenbroek isc_time_set(isc_time_t *t, unsigned int seconds, unsigned int nanoseconds) {
122*00b67f09SDavid van Moolenbroek 	REQUIRE(t != NULL);
123*00b67f09SDavid van Moolenbroek 	REQUIRE(nanoseconds < NS_PER_S);
124*00b67f09SDavid van Moolenbroek 
125*00b67f09SDavid van Moolenbroek 	t->seconds = seconds;
126*00b67f09SDavid van Moolenbroek 	t->nanoseconds = nanoseconds;
127*00b67f09SDavid van Moolenbroek }
128*00b67f09SDavid van Moolenbroek 
129*00b67f09SDavid van Moolenbroek void
isc_time_settoepoch(isc_time_t * t)130*00b67f09SDavid van Moolenbroek isc_time_settoepoch(isc_time_t *t) {
131*00b67f09SDavid van Moolenbroek 	REQUIRE(t != NULL);
132*00b67f09SDavid van Moolenbroek 
133*00b67f09SDavid van Moolenbroek 	t->seconds = 0;
134*00b67f09SDavid van Moolenbroek 	t->nanoseconds = 0;
135*00b67f09SDavid van Moolenbroek }
136*00b67f09SDavid van Moolenbroek 
137*00b67f09SDavid van Moolenbroek isc_boolean_t
isc_time_isepoch(const isc_time_t * t)138*00b67f09SDavid van Moolenbroek isc_time_isepoch(const isc_time_t *t) {
139*00b67f09SDavid van Moolenbroek 	REQUIRE(t != NULL);
140*00b67f09SDavid van Moolenbroek 	INSIST(t->nanoseconds < NS_PER_S);
141*00b67f09SDavid van Moolenbroek 
142*00b67f09SDavid van Moolenbroek 	if (t->seconds == 0 && t->nanoseconds == 0)
143*00b67f09SDavid van Moolenbroek 		return (ISC_TRUE);
144*00b67f09SDavid van Moolenbroek 
145*00b67f09SDavid van Moolenbroek 	return (ISC_FALSE);
146*00b67f09SDavid van Moolenbroek }
147*00b67f09SDavid van Moolenbroek 
148*00b67f09SDavid van Moolenbroek 
149*00b67f09SDavid van Moolenbroek isc_result_t
isc_time_now(isc_time_t * t)150*00b67f09SDavid van Moolenbroek isc_time_now(isc_time_t *t) {
151*00b67f09SDavid van Moolenbroek 	struct timeval tv;
152*00b67f09SDavid van Moolenbroek 	char strbuf[ISC_STRERRORSIZE];
153*00b67f09SDavid van Moolenbroek 
154*00b67f09SDavid van Moolenbroek 	REQUIRE(t != NULL);
155*00b67f09SDavid van Moolenbroek 
156*00b67f09SDavid van Moolenbroek 	if (gettimeofday(&tv, NULL) == -1) {
157*00b67f09SDavid van Moolenbroek 		isc__strerror(errno, strbuf, sizeof(strbuf));
158*00b67f09SDavid van Moolenbroek 		UNEXPECTED_ERROR(__FILE__, __LINE__, "%s", strbuf);
159*00b67f09SDavid van Moolenbroek 		return (ISC_R_UNEXPECTED);
160*00b67f09SDavid van Moolenbroek 	}
161*00b67f09SDavid van Moolenbroek 
162*00b67f09SDavid van Moolenbroek 	/*
163*00b67f09SDavid van Moolenbroek 	 * Does POSIX guarantee the signedness of tv_sec and tv_usec?  If not,
164*00b67f09SDavid van Moolenbroek 	 * then this test will generate warnings for platforms on which it is
165*00b67f09SDavid van Moolenbroek 	 * unsigned.  In any event, the chances of any of these problems
166*00b67f09SDavid van Moolenbroek 	 * happening are pretty much zero, but since the libisc library ensures
167*00b67f09SDavid van Moolenbroek 	 * certain things to be true ...
168*00b67f09SDavid van Moolenbroek 	 */
169*00b67f09SDavid van Moolenbroek #if ISC_FIX_TV_USEC
170*00b67f09SDavid van Moolenbroek 	fix_tv_usec(&tv);
171*00b67f09SDavid van Moolenbroek 	if (tv.tv_sec < 0)
172*00b67f09SDavid van Moolenbroek 		return (ISC_R_UNEXPECTED);
173*00b67f09SDavid van Moolenbroek #else
174*00b67f09SDavid van Moolenbroek 	if (tv.tv_sec < 0 || tv.tv_usec < 0 || tv.tv_usec >= US_PER_S)
175*00b67f09SDavid van Moolenbroek 		return (ISC_R_UNEXPECTED);
176*00b67f09SDavid van Moolenbroek #endif
177*00b67f09SDavid van Moolenbroek 
178*00b67f09SDavid van Moolenbroek 	/*
179*00b67f09SDavid van Moolenbroek 	 * Ensure the tv_sec value fits in t->seconds.
180*00b67f09SDavid van Moolenbroek 	 */
181*00b67f09SDavid van Moolenbroek 	if (sizeof(tv.tv_sec) > sizeof(t->seconds) &&
182*00b67f09SDavid van Moolenbroek 	    ((tv.tv_sec | (unsigned int)-1) ^ (unsigned int)-1) != 0U)
183*00b67f09SDavid van Moolenbroek 		return (ISC_R_RANGE);
184*00b67f09SDavid van Moolenbroek 
185*00b67f09SDavid van Moolenbroek 	t->seconds = tv.tv_sec;
186*00b67f09SDavid van Moolenbroek 	t->nanoseconds = tv.tv_usec * NS_PER_US;
187*00b67f09SDavid van Moolenbroek 
188*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
189*00b67f09SDavid van Moolenbroek }
190*00b67f09SDavid van Moolenbroek 
191*00b67f09SDavid van Moolenbroek isc_result_t
isc_time_nowplusinterval(isc_time_t * t,const isc_interval_t * i)192*00b67f09SDavid van Moolenbroek isc_time_nowplusinterval(isc_time_t *t, const isc_interval_t *i) {
193*00b67f09SDavid van Moolenbroek 	struct timeval tv;
194*00b67f09SDavid van Moolenbroek 	char strbuf[ISC_STRERRORSIZE];
195*00b67f09SDavid van Moolenbroek 
196*00b67f09SDavid van Moolenbroek 	REQUIRE(t != NULL);
197*00b67f09SDavid van Moolenbroek 	REQUIRE(i != NULL);
198*00b67f09SDavid van Moolenbroek 	INSIST(i->nanoseconds < NS_PER_S);
199*00b67f09SDavid van Moolenbroek 
200*00b67f09SDavid van Moolenbroek 	if (gettimeofday(&tv, NULL) == -1) {
201*00b67f09SDavid van Moolenbroek 		isc__strerror(errno, strbuf, sizeof(strbuf));
202*00b67f09SDavid van Moolenbroek 		UNEXPECTED_ERROR(__FILE__, __LINE__, "%s", strbuf);
203*00b67f09SDavid van Moolenbroek 		return (ISC_R_UNEXPECTED);
204*00b67f09SDavid van Moolenbroek 	}
205*00b67f09SDavid van Moolenbroek 
206*00b67f09SDavid van Moolenbroek 	/*
207*00b67f09SDavid van Moolenbroek 	 * Does POSIX guarantee the signedness of tv_sec and tv_usec?  If not,
208*00b67f09SDavid van Moolenbroek 	 * then this test will generate warnings for platforms on which it is
209*00b67f09SDavid van Moolenbroek 	 * unsigned.  In any event, the chances of any of these problems
210*00b67f09SDavid van Moolenbroek 	 * happening are pretty much zero, but since the libisc library ensures
211*00b67f09SDavid van Moolenbroek 	 * certain things to be true ...
212*00b67f09SDavid van Moolenbroek 	 */
213*00b67f09SDavid van Moolenbroek #if ISC_FIX_TV_USEC
214*00b67f09SDavid van Moolenbroek 	fix_tv_usec(&tv);
215*00b67f09SDavid van Moolenbroek 	if (tv.tv_sec < 0)
216*00b67f09SDavid van Moolenbroek 		return (ISC_R_UNEXPECTED);
217*00b67f09SDavid van Moolenbroek #else
218*00b67f09SDavid van Moolenbroek 	if (tv.tv_sec < 0 || tv.tv_usec < 0 || tv.tv_usec >= US_PER_S)
219*00b67f09SDavid van Moolenbroek 		return (ISC_R_UNEXPECTED);
220*00b67f09SDavid van Moolenbroek #endif
221*00b67f09SDavid van Moolenbroek 
222*00b67f09SDavid van Moolenbroek 	/*
223*00b67f09SDavid van Moolenbroek 	 * Ensure the resulting seconds value fits in the size of an
224*00b67f09SDavid van Moolenbroek 	 * unsigned int.  (It is written this way as a slight optimization;
225*00b67f09SDavid van Moolenbroek 	 * note that even if both values == INT_MAX, then when added
226*00b67f09SDavid van Moolenbroek 	 * and getting another 1 added below the result is UINT_MAX.)
227*00b67f09SDavid van Moolenbroek 	 */
228*00b67f09SDavid van Moolenbroek 	if ((tv.tv_sec > INT_MAX || i->seconds > INT_MAX) &&
229*00b67f09SDavid van Moolenbroek 	    ((long long)tv.tv_sec + i->seconds > UINT_MAX))
230*00b67f09SDavid van Moolenbroek 		return (ISC_R_RANGE);
231*00b67f09SDavid van Moolenbroek 
232*00b67f09SDavid van Moolenbroek 	t->seconds = tv.tv_sec + i->seconds;
233*00b67f09SDavid van Moolenbroek 	t->nanoseconds = tv.tv_usec * NS_PER_US + i->nanoseconds;
234*00b67f09SDavid van Moolenbroek 	if (t->nanoseconds >= NS_PER_S) {
235*00b67f09SDavid van Moolenbroek 		t->seconds++;
236*00b67f09SDavid van Moolenbroek 		t->nanoseconds -= NS_PER_S;
237*00b67f09SDavid van Moolenbroek 	}
238*00b67f09SDavid van Moolenbroek 
239*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
240*00b67f09SDavid van Moolenbroek }
241*00b67f09SDavid van Moolenbroek 
242*00b67f09SDavid van Moolenbroek int
isc_time_compare(const isc_time_t * t1,const isc_time_t * t2)243*00b67f09SDavid van Moolenbroek isc_time_compare(const isc_time_t *t1, const isc_time_t *t2) {
244*00b67f09SDavid van Moolenbroek 	REQUIRE(t1 != NULL && t2 != NULL);
245*00b67f09SDavid van Moolenbroek 	INSIST(t1->nanoseconds < NS_PER_S && t2->nanoseconds < NS_PER_S);
246*00b67f09SDavid van Moolenbroek 
247*00b67f09SDavid van Moolenbroek 	if (t1->seconds < t2->seconds)
248*00b67f09SDavid van Moolenbroek 		return (-1);
249*00b67f09SDavid van Moolenbroek 	if (t1->seconds > t2->seconds)
250*00b67f09SDavid van Moolenbroek 		return (1);
251*00b67f09SDavid van Moolenbroek 	if (t1->nanoseconds < t2->nanoseconds)
252*00b67f09SDavid van Moolenbroek 		return (-1);
253*00b67f09SDavid van Moolenbroek 	if (t1->nanoseconds > t2->nanoseconds)
254*00b67f09SDavid van Moolenbroek 		return (1);
255*00b67f09SDavid van Moolenbroek 	return (0);
256*00b67f09SDavid van Moolenbroek }
257*00b67f09SDavid van Moolenbroek 
258*00b67f09SDavid van Moolenbroek isc_result_t
isc_time_add(const isc_time_t * t,const isc_interval_t * i,isc_time_t * result)259*00b67f09SDavid van Moolenbroek isc_time_add(const isc_time_t *t, const isc_interval_t *i, isc_time_t *result)
260*00b67f09SDavid van Moolenbroek {
261*00b67f09SDavid van Moolenbroek 	REQUIRE(t != NULL && i != NULL && result != NULL);
262*00b67f09SDavid van Moolenbroek 	INSIST(t->nanoseconds < NS_PER_S && i->nanoseconds < NS_PER_S);
263*00b67f09SDavid van Moolenbroek 
264*00b67f09SDavid van Moolenbroek 	/*
265*00b67f09SDavid van Moolenbroek 	 * Ensure the resulting seconds value fits in the size of an
266*00b67f09SDavid van Moolenbroek 	 * unsigned int.  (It is written this way as a slight optimization;
267*00b67f09SDavid van Moolenbroek 	 * note that even if both values == INT_MAX, then when added
268*00b67f09SDavid van Moolenbroek 	 * and getting another 1 added below the result is UINT_MAX.)
269*00b67f09SDavid van Moolenbroek 	 */
270*00b67f09SDavid van Moolenbroek 	if ((t->seconds > INT_MAX || i->seconds > INT_MAX) &&
271*00b67f09SDavid van Moolenbroek 	    ((long long)t->seconds + i->seconds > UINT_MAX))
272*00b67f09SDavid van Moolenbroek 		return (ISC_R_RANGE);
273*00b67f09SDavid van Moolenbroek 
274*00b67f09SDavid van Moolenbroek 	result->seconds = t->seconds + i->seconds;
275*00b67f09SDavid van Moolenbroek 	result->nanoseconds = t->nanoseconds + i->nanoseconds;
276*00b67f09SDavid van Moolenbroek 	if (result->nanoseconds >= NS_PER_S) {
277*00b67f09SDavid van Moolenbroek 		result->seconds++;
278*00b67f09SDavid van Moolenbroek 		result->nanoseconds -= NS_PER_S;
279*00b67f09SDavid van Moolenbroek 	}
280*00b67f09SDavid van Moolenbroek 
281*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
282*00b67f09SDavid van Moolenbroek }
283*00b67f09SDavid van Moolenbroek 
284*00b67f09SDavid van Moolenbroek isc_result_t
isc_time_subtract(const isc_time_t * t,const isc_interval_t * i,isc_time_t * result)285*00b67f09SDavid van Moolenbroek isc_time_subtract(const isc_time_t *t, const isc_interval_t *i,
286*00b67f09SDavid van Moolenbroek 		  isc_time_t *result)
287*00b67f09SDavid van Moolenbroek {
288*00b67f09SDavid van Moolenbroek 	REQUIRE(t != NULL && i != NULL && result != NULL);
289*00b67f09SDavid van Moolenbroek 	INSIST(t->nanoseconds < NS_PER_S && i->nanoseconds < NS_PER_S);
290*00b67f09SDavid van Moolenbroek 
291*00b67f09SDavid van Moolenbroek 	if ((unsigned int)t->seconds < i->seconds ||
292*00b67f09SDavid van Moolenbroek 	    ((unsigned int)t->seconds == i->seconds &&
293*00b67f09SDavid van Moolenbroek 	     t->nanoseconds < i->nanoseconds))
294*00b67f09SDavid van Moolenbroek 	    return (ISC_R_RANGE);
295*00b67f09SDavid van Moolenbroek 
296*00b67f09SDavid van Moolenbroek 	result->seconds = t->seconds - i->seconds;
297*00b67f09SDavid van Moolenbroek 	if (t->nanoseconds >= i->nanoseconds)
298*00b67f09SDavid van Moolenbroek 		result->nanoseconds = t->nanoseconds - i->nanoseconds;
299*00b67f09SDavid van Moolenbroek 	else {
300*00b67f09SDavid van Moolenbroek 		result->nanoseconds = NS_PER_S - i->nanoseconds +
301*00b67f09SDavid van Moolenbroek 			t->nanoseconds;
302*00b67f09SDavid van Moolenbroek 		result->seconds--;
303*00b67f09SDavid van Moolenbroek 	}
304*00b67f09SDavid van Moolenbroek 
305*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
306*00b67f09SDavid van Moolenbroek }
307*00b67f09SDavid van Moolenbroek 
308*00b67f09SDavid van Moolenbroek isc_uint64_t
isc_time_microdiff(const isc_time_t * t1,const isc_time_t * t2)309*00b67f09SDavid van Moolenbroek isc_time_microdiff(const isc_time_t *t1, const isc_time_t *t2) {
310*00b67f09SDavid van Moolenbroek 	isc_uint64_t i1, i2, i3;
311*00b67f09SDavid van Moolenbroek 
312*00b67f09SDavid van Moolenbroek 	REQUIRE(t1 != NULL && t2 != NULL);
313*00b67f09SDavid van Moolenbroek 	INSIST(t1->nanoseconds < NS_PER_S && t2->nanoseconds < NS_PER_S);
314*00b67f09SDavid van Moolenbroek 
315*00b67f09SDavid van Moolenbroek 	i1 = (isc_uint64_t)t1->seconds * NS_PER_S + t1->nanoseconds;
316*00b67f09SDavid van Moolenbroek 	i2 = (isc_uint64_t)t2->seconds * NS_PER_S + t2->nanoseconds;
317*00b67f09SDavid van Moolenbroek 
318*00b67f09SDavid van Moolenbroek 	if (i1 <= i2)
319*00b67f09SDavid van Moolenbroek 		return (0);
320*00b67f09SDavid van Moolenbroek 
321*00b67f09SDavid van Moolenbroek 	i3 = i1 - i2;
322*00b67f09SDavid van Moolenbroek 
323*00b67f09SDavid van Moolenbroek 	/*
324*00b67f09SDavid van Moolenbroek 	 * Convert to microseconds.
325*00b67f09SDavid van Moolenbroek 	 */
326*00b67f09SDavid van Moolenbroek 	i3 /= NS_PER_US;
327*00b67f09SDavid van Moolenbroek 
328*00b67f09SDavid van Moolenbroek 	return (i3);
329*00b67f09SDavid van Moolenbroek }
330*00b67f09SDavid van Moolenbroek 
331*00b67f09SDavid van Moolenbroek isc_uint32_t
isc_time_seconds(const isc_time_t * t)332*00b67f09SDavid van Moolenbroek isc_time_seconds(const isc_time_t *t) {
333*00b67f09SDavid van Moolenbroek 	REQUIRE(t != NULL);
334*00b67f09SDavid van Moolenbroek 	INSIST(t->nanoseconds < NS_PER_S);
335*00b67f09SDavid van Moolenbroek 
336*00b67f09SDavid van Moolenbroek 	return ((isc_uint32_t)t->seconds);
337*00b67f09SDavid van Moolenbroek }
338*00b67f09SDavid van Moolenbroek 
339*00b67f09SDavid van Moolenbroek isc_result_t
isc_time_secondsastimet(const isc_time_t * t,time_t * secondsp)340*00b67f09SDavid van Moolenbroek isc_time_secondsastimet(const isc_time_t *t, time_t *secondsp) {
341*00b67f09SDavid van Moolenbroek 	time_t seconds, i;
342*00b67f09SDavid van Moolenbroek 
343*00b67f09SDavid van Moolenbroek 	REQUIRE(t != NULL);
344*00b67f09SDavid van Moolenbroek 	INSIST(t->nanoseconds < NS_PER_S);
345*00b67f09SDavid van Moolenbroek 
346*00b67f09SDavid van Moolenbroek 	/*
347*00b67f09SDavid van Moolenbroek 	 * Ensure that the number of seconds represented by t->seconds
348*00b67f09SDavid van Moolenbroek 	 * can be represented by a time_t.  Since t->seconds is an unsigned
349*00b67f09SDavid van Moolenbroek 	 * int and since time_t is mostly opaque, this is trickier than
350*00b67f09SDavid van Moolenbroek 	 * it seems.  (This standardized opaqueness of time_t is *very*
351*00b67f09SDavid van Moolenbroek 	 * frustrating; time_t is not even limited to being an integral
352*00b67f09SDavid van Moolenbroek 	 * type.)
353*00b67f09SDavid van Moolenbroek 	 *
354*00b67f09SDavid van Moolenbroek 	 * The mission, then, is to avoid generating any kind of warning
355*00b67f09SDavid van Moolenbroek 	 * about "signed versus unsigned" while trying to determine if the
356*00b67f09SDavid van Moolenbroek 	 * the unsigned int t->seconds is out range for tv_sec, which is
357*00b67f09SDavid van Moolenbroek 	 * pretty much only true if time_t is a signed integer of the same
358*00b67f09SDavid van Moolenbroek 	 * size as the return value of isc_time_seconds.
359*00b67f09SDavid van Moolenbroek 	 *
360*00b67f09SDavid van Moolenbroek 	 * If the paradox in the if clause below is true, t->seconds is out
361*00b67f09SDavid van Moolenbroek 	 * of range for time_t.
362*00b67f09SDavid van Moolenbroek 	 */
363*00b67f09SDavid van Moolenbroek 	seconds = (time_t)t->seconds;
364*00b67f09SDavid van Moolenbroek 
365*00b67f09SDavid van Moolenbroek 	INSIST(sizeof(unsigned int) == sizeof(isc_uint32_t));
366*00b67f09SDavid van Moolenbroek 	INSIST(sizeof(time_t) >= sizeof(isc_uint32_t));
367*00b67f09SDavid van Moolenbroek 
368*00b67f09SDavid van Moolenbroek 	if (sizeof(time_t) == sizeof(isc_uint32_t) &&	       /* Same size. */
369*00b67f09SDavid van Moolenbroek 	    (time_t)0.5 != 0.5 &&	       /* Not a floating point type. */
370*00b67f09SDavid van Moolenbroek 	    (i = (time_t)-1) != 4294967295u &&		       /* Is signed. */
371*00b67f09SDavid van Moolenbroek 	    (seconds &
372*00b67f09SDavid van Moolenbroek 	     (1ULL << (sizeof(time_t) * CHAR_BIT - 1))) != 0ULL) {   /* Negative. */
373*00b67f09SDavid van Moolenbroek 		/*
374*00b67f09SDavid van Moolenbroek 		 * This UNUSED() is here to shut up the IRIX compiler:
375*00b67f09SDavid van Moolenbroek 		 *	variable "i" was set but never used
376*00b67f09SDavid van Moolenbroek 		 * when the value of i *was* used in the third test.
377*00b67f09SDavid van Moolenbroek 		 * (Let's hope the compiler got the actual test right.)
378*00b67f09SDavid van Moolenbroek 		 */
379*00b67f09SDavid van Moolenbroek 		UNUSED(i);
380*00b67f09SDavid van Moolenbroek 		return (ISC_R_RANGE);
381*00b67f09SDavid van Moolenbroek 	}
382*00b67f09SDavid van Moolenbroek 
383*00b67f09SDavid van Moolenbroek 	*secondsp = seconds;
384*00b67f09SDavid van Moolenbroek 
385*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
386*00b67f09SDavid van Moolenbroek }
387*00b67f09SDavid van Moolenbroek 
388*00b67f09SDavid van Moolenbroek isc_uint32_t
isc_time_nanoseconds(const isc_time_t * t)389*00b67f09SDavid van Moolenbroek isc_time_nanoseconds(const isc_time_t *t) {
390*00b67f09SDavid van Moolenbroek 	REQUIRE(t != NULL);
391*00b67f09SDavid van Moolenbroek 
392*00b67f09SDavid van Moolenbroek 	ENSURE(t->nanoseconds < NS_PER_S);
393*00b67f09SDavid van Moolenbroek 
394*00b67f09SDavid van Moolenbroek 	return ((isc_uint32_t)t->nanoseconds);
395*00b67f09SDavid van Moolenbroek }
396*00b67f09SDavid van Moolenbroek 
397*00b67f09SDavid van Moolenbroek void
isc_time_formattimestamp(const isc_time_t * t,char * buf,unsigned int len)398*00b67f09SDavid van Moolenbroek isc_time_formattimestamp(const isc_time_t *t, char *buf, unsigned int len) {
399*00b67f09SDavid van Moolenbroek 	time_t now;
400*00b67f09SDavid van Moolenbroek 	unsigned int flen;
401*00b67f09SDavid van Moolenbroek 
402*00b67f09SDavid van Moolenbroek 	REQUIRE(len > 0);
403*00b67f09SDavid van Moolenbroek 
404*00b67f09SDavid van Moolenbroek 	now = (time_t) t->seconds;
405*00b67f09SDavid van Moolenbroek 	flen = strftime(buf, len, "%d-%b-%Y %X", localtime(&now));
406*00b67f09SDavid van Moolenbroek 	INSIST(flen < len);
407*00b67f09SDavid van Moolenbroek 	if (flen != 0)
408*00b67f09SDavid van Moolenbroek 		snprintf(buf + flen, len - flen,
409*00b67f09SDavid van Moolenbroek 			 ".%03u", t->nanoseconds / 1000000);
410*00b67f09SDavid van Moolenbroek 	else
411*00b67f09SDavid van Moolenbroek 		snprintf(buf, len, "99-Bad-9999 99:99:99.999");
412*00b67f09SDavid van Moolenbroek }
413*00b67f09SDavid van Moolenbroek 
414*00b67f09SDavid van Moolenbroek void
isc_time_formathttptimestamp(const isc_time_t * t,char * buf,unsigned int len)415*00b67f09SDavid van Moolenbroek isc_time_formathttptimestamp(const isc_time_t *t, char *buf, unsigned int len) {
416*00b67f09SDavid van Moolenbroek 	time_t now;
417*00b67f09SDavid van Moolenbroek 	unsigned int flen;
418*00b67f09SDavid van Moolenbroek 
419*00b67f09SDavid van Moolenbroek 	REQUIRE(len > 0);
420*00b67f09SDavid van Moolenbroek 
421*00b67f09SDavid van Moolenbroek 	/*
422*00b67f09SDavid van Moolenbroek 	 * 5 spaces, 1 comma, 3 GMT, 2 %d, 4 %Y, 8 %H:%M:%S, 3+ %a, 3+ %b (29+)
423*00b67f09SDavid van Moolenbroek 	 */
424*00b67f09SDavid van Moolenbroek 	now = (time_t)t->seconds;
425*00b67f09SDavid van Moolenbroek 	flen = strftime(buf, len, "%a, %d %b %Y %H:%M:%S GMT", gmtime(&now));
426*00b67f09SDavid van Moolenbroek 	INSIST(flen < len);
427*00b67f09SDavid van Moolenbroek }
428*00b67f09SDavid van Moolenbroek 
429*00b67f09SDavid van Moolenbroek isc_result_t
isc_time_parsehttptimestamp(char * buf,isc_time_t * t)430*00b67f09SDavid van Moolenbroek isc_time_parsehttptimestamp(char *buf, isc_time_t *t) {
431*00b67f09SDavid van Moolenbroek 	struct tm t_tm;
432*00b67f09SDavid van Moolenbroek 	time_t when;
433*00b67f09SDavid van Moolenbroek 	char *p;
434*00b67f09SDavid van Moolenbroek 
435*00b67f09SDavid van Moolenbroek 	REQUIRE(buf != NULL);
436*00b67f09SDavid van Moolenbroek 	REQUIRE(t != NULL);
437*00b67f09SDavid van Moolenbroek 	p = isc_tm_strptime(buf, "%a, %d %b %Y %H:%M:%S", &t_tm);
438*00b67f09SDavid van Moolenbroek 	if (p == NULL)
439*00b67f09SDavid van Moolenbroek 		return (ISC_R_UNEXPECTED);
440*00b67f09SDavid van Moolenbroek 	when = isc_tm_timegm(&t_tm);
441*00b67f09SDavid van Moolenbroek 	if (when == -1)
442*00b67f09SDavid van Moolenbroek 		return (ISC_R_UNEXPECTED);
443*00b67f09SDavid van Moolenbroek 	isc_time_set(t, when, 0);
444*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
445*00b67f09SDavid van Moolenbroek }
446*00b67f09SDavid van Moolenbroek 
447*00b67f09SDavid van Moolenbroek void
isc_time_formatISO8601(const isc_time_t * t,char * buf,unsigned int len)448*00b67f09SDavid van Moolenbroek isc_time_formatISO8601(const isc_time_t *t, char *buf, unsigned int len) {
449*00b67f09SDavid van Moolenbroek 	time_t now;
450*00b67f09SDavid van Moolenbroek 	unsigned int flen;
451*00b67f09SDavid van Moolenbroek 
452*00b67f09SDavid van Moolenbroek 	REQUIRE(len > 0);
453*00b67f09SDavid van Moolenbroek 
454*00b67f09SDavid van Moolenbroek 	now = (time_t)t->seconds;
455*00b67f09SDavid van Moolenbroek 	flen = strftime(buf, len, "%Y-%m-%dT%H:%M:%SZ", gmtime(&now));
456*00b67f09SDavid van Moolenbroek 	INSIST(flen < len);
457*00b67f09SDavid van Moolenbroek }
458