1 /* $NetBSD: time.c,v 1.9 2015/07/08 17:29:00 christos Exp $ */
4 * Copyright (C) 2004-2008, 2011, 2012, 2014, 2015 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 1998-2001, 2003 Internet Software Consortium.
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.
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.
32 #include <sys/time.h> /* Required for struct timeval on some platforms. */
35 #include <isc/print.h>
36 #include <isc/strerror.h>
37 #include <isc/string.h>
42 #define NS_PER_S 1000000000 /*%< Nanoseconds per second. */
43 #define NS_PER_US 1000 /*%< Nanoseconds per microsecond. */
44 #define US_PER_S 1000000 /*%< Microseconds per second. */
47 * All of the INSIST()s checks of nanoseconds < NS_PER_S are for
48 * consistency checking of the type. In lieu of magic numbers, it
49 * is the best we've got. The check is only performed on functions which
50 * need an initialized type.
53 #ifndef ISC_FIX_TV_USEC
54 #define ISC_FIX_TV_USEC 1
61 static const isc_interval_t zero_interval
= { 0, 0 };
62 const isc_interval_t
* const isc_interval_zero
= &zero_interval
;
66 fix_tv_usec(struct timeval
*tv
) {
67 isc_boolean_t fixed
= ISC_FALSE
;
69 if (tv
->tv_usec
< 0) {
73 tv
->tv_usec
+= US_PER_S
;
74 } while (tv
->tv_usec
< 0);
75 } else if (tv
->tv_usec
>= US_PER_S
) {
79 tv
->tv_usec
-= US_PER_S
;
80 } while (tv
->tv_usec
>=US_PER_S
);
83 * Call syslog directly as was are called from the logging functions.
86 (void)syslog(LOG_ERR
, "gettimeofday returned bad tv_usec: corrected");
91 isc_interval_set(isc_interval_t
*i
,
92 unsigned int seconds
, unsigned int nanoseconds
)
95 REQUIRE(nanoseconds
< NS_PER_S
);
98 i
->nanoseconds
= nanoseconds
;
102 isc_interval_iszero(const isc_interval_t
*i
) {
104 INSIST(i
->nanoseconds
< NS_PER_S
);
106 if (i
->seconds
== 0 && i
->nanoseconds
== 0)
117 static const isc_time_t epoch
= { 0, 0 };
118 const isc_time_t
* const isc_time_epoch
= &epoch
;
121 isc_time_set(isc_time_t
*t
, unsigned int seconds
, unsigned int nanoseconds
) {
123 REQUIRE(nanoseconds
< NS_PER_S
);
125 t
->seconds
= seconds
;
126 t
->nanoseconds
= nanoseconds
;
130 isc_time_settoepoch(isc_time_t
*t
) {
138 isc_time_isepoch(const isc_time_t
*t
) {
140 INSIST(t
->nanoseconds
< NS_PER_S
);
142 if (t
->seconds
== 0 && t
->nanoseconds
== 0)
150 isc_time_now(isc_time_t
*t
) {
152 char strbuf
[ISC_STRERRORSIZE
];
156 if (gettimeofday(&tv
, NULL
) == -1) {
157 isc__strerror(errno
, strbuf
, sizeof(strbuf
));
158 UNEXPECTED_ERROR(__FILE__
, __LINE__
, "%s", strbuf
);
159 return (ISC_R_UNEXPECTED
);
163 * Does POSIX guarantee the signedness of tv_sec and tv_usec? If not,
164 * then this test will generate warnings for platforms on which it is
165 * unsigned. In any event, the chances of any of these problems
166 * happening are pretty much zero, but since the libisc library ensures
167 * certain things to be true ...
172 return (ISC_R_UNEXPECTED
);
174 if (tv
.tv_sec
< 0 || tv
.tv_usec
< 0 || tv
.tv_usec
>= US_PER_S
)
175 return (ISC_R_UNEXPECTED
);
179 * Ensure the tv_sec value fits in t->seconds.
181 if (sizeof(tv
.tv_sec
) > sizeof(t
->seconds
) &&
182 ((tv
.tv_sec
| (unsigned int)-1) ^ (unsigned int)-1) != 0U)
183 return (ISC_R_RANGE
);
185 t
->seconds
= tv
.tv_sec
;
186 t
->nanoseconds
= tv
.tv_usec
* NS_PER_US
;
188 return (ISC_R_SUCCESS
);
192 isc_time_nowplusinterval(isc_time_t
*t
, const isc_interval_t
*i
) {
194 char strbuf
[ISC_STRERRORSIZE
];
198 INSIST(i
->nanoseconds
< NS_PER_S
);
200 if (gettimeofday(&tv
, NULL
) == -1) {
201 isc__strerror(errno
, strbuf
, sizeof(strbuf
));
202 UNEXPECTED_ERROR(__FILE__
, __LINE__
, "%s", strbuf
);
203 return (ISC_R_UNEXPECTED
);
207 * Does POSIX guarantee the signedness of tv_sec and tv_usec? If not,
208 * then this test will generate warnings for platforms on which it is
209 * unsigned. In any event, the chances of any of these problems
210 * happening are pretty much zero, but since the libisc library ensures
211 * certain things to be true ...
216 return (ISC_R_UNEXPECTED
);
218 if (tv
.tv_sec
< 0 || tv
.tv_usec
< 0 || tv
.tv_usec
>= US_PER_S
)
219 return (ISC_R_UNEXPECTED
);
223 * Ensure the resulting seconds value fits in the size of an
224 * unsigned int. (It is written this way as a slight optimization;
225 * note that even if both values == INT_MAX, then when added
226 * and getting another 1 added below the result is UINT_MAX.)
228 if ((tv
.tv_sec
> INT_MAX
|| i
->seconds
> INT_MAX
) &&
229 ((long long)tv
.tv_sec
+ i
->seconds
> UINT_MAX
))
230 return (ISC_R_RANGE
);
232 t
->seconds
= tv
.tv_sec
+ i
->seconds
;
233 t
->nanoseconds
= tv
.tv_usec
* NS_PER_US
+ i
->nanoseconds
;
234 if (t
->nanoseconds
>= NS_PER_S
) {
236 t
->nanoseconds
-= NS_PER_S
;
239 return (ISC_R_SUCCESS
);
243 isc_time_compare(const isc_time_t
*t1
, const isc_time_t
*t2
) {
244 REQUIRE(t1
!= NULL
&& t2
!= NULL
);
245 INSIST(t1
->nanoseconds
< NS_PER_S
&& t2
->nanoseconds
< NS_PER_S
);
247 if (t1
->seconds
< t2
->seconds
)
249 if (t1
->seconds
> t2
->seconds
)
251 if (t1
->nanoseconds
< t2
->nanoseconds
)
253 if (t1
->nanoseconds
> t2
->nanoseconds
)
259 isc_time_add(const isc_time_t
*t
, const isc_interval_t
*i
, isc_time_t
*result
)
261 REQUIRE(t
!= NULL
&& i
!= NULL
&& result
!= NULL
);
262 INSIST(t
->nanoseconds
< NS_PER_S
&& i
->nanoseconds
< NS_PER_S
);
265 * Ensure the resulting seconds value fits in the size of an
266 * unsigned int. (It is written this way as a slight optimization;
267 * note that even if both values == INT_MAX, then when added
268 * and getting another 1 added below the result is UINT_MAX.)
270 if ((t
->seconds
> INT_MAX
|| i
->seconds
> INT_MAX
) &&
271 ((long long)t
->seconds
+ i
->seconds
> UINT_MAX
))
272 return (ISC_R_RANGE
);
274 result
->seconds
= t
->seconds
+ i
->seconds
;
275 result
->nanoseconds
= t
->nanoseconds
+ i
->nanoseconds
;
276 if (result
->nanoseconds
>= NS_PER_S
) {
278 result
->nanoseconds
-= NS_PER_S
;
281 return (ISC_R_SUCCESS
);
285 isc_time_subtract(const isc_time_t
*t
, const isc_interval_t
*i
,
288 REQUIRE(t
!= NULL
&& i
!= NULL
&& result
!= NULL
);
289 INSIST(t
->nanoseconds
< NS_PER_S
&& i
->nanoseconds
< NS_PER_S
);
291 if ((unsigned int)t
->seconds
< i
->seconds
||
292 ((unsigned int)t
->seconds
== i
->seconds
&&
293 t
->nanoseconds
< i
->nanoseconds
))
294 return (ISC_R_RANGE
);
296 result
->seconds
= t
->seconds
- i
->seconds
;
297 if (t
->nanoseconds
>= i
->nanoseconds
)
298 result
->nanoseconds
= t
->nanoseconds
- i
->nanoseconds
;
300 result
->nanoseconds
= NS_PER_S
- i
->nanoseconds
+
305 return (ISC_R_SUCCESS
);
309 isc_time_microdiff(const isc_time_t
*t1
, const isc_time_t
*t2
) {
310 isc_uint64_t i1
, i2
, i3
;
312 REQUIRE(t1
!= NULL
&& t2
!= NULL
);
313 INSIST(t1
->nanoseconds
< NS_PER_S
&& t2
->nanoseconds
< NS_PER_S
);
315 i1
= (isc_uint64_t
)t1
->seconds
* NS_PER_S
+ t1
->nanoseconds
;
316 i2
= (isc_uint64_t
)t2
->seconds
* NS_PER_S
+ t2
->nanoseconds
;
324 * Convert to microseconds.
332 isc_time_seconds(const isc_time_t
*t
) {
334 INSIST(t
->nanoseconds
< NS_PER_S
);
336 return ((isc_uint32_t
)t
->seconds
);
340 isc_time_secondsastimet(const isc_time_t
*t
, time_t *secondsp
) {
344 INSIST(t
->nanoseconds
< NS_PER_S
);
347 * Ensure that the number of seconds represented by t->seconds
348 * can be represented by a time_t. Since t->seconds is an unsigned
349 * int and since time_t is mostly opaque, this is trickier than
350 * it seems. (This standardized opaqueness of time_t is *very*
351 * frustrating; time_t is not even limited to being an integral
354 * The mission, then, is to avoid generating any kind of warning
355 * about "signed versus unsigned" while trying to determine if the
356 * the unsigned int t->seconds is out range for tv_sec, which is
357 * pretty much only true if time_t is a signed integer of the same
358 * size as the return value of isc_time_seconds.
360 * If the paradox in the if clause below is true, t->seconds is out
361 * of range for time_t.
363 seconds
= (time_t)t
->seconds
;
365 INSIST(sizeof(unsigned int) == sizeof(isc_uint32_t
));
366 INSIST(sizeof(time_t) >= sizeof(isc_uint32_t
));
368 if (sizeof(time_t) == sizeof(isc_uint32_t
) && /* Same size. */
369 (time_t)0.5 != 0.5 && /* Not a floating point type. */
370 (i
= (time_t)-1) != 4294967295u && /* Is signed. */
372 (1ULL << (sizeof(time_t) * CHAR_BIT
- 1))) != 0ULL) { /* Negative. */
374 * This UNUSED() is here to shut up the IRIX compiler:
375 * variable "i" was set but never used
376 * when the value of i *was* used in the third test.
377 * (Let's hope the compiler got the actual test right.)
380 return (ISC_R_RANGE
);
385 return (ISC_R_SUCCESS
);
389 isc_time_nanoseconds(const isc_time_t
*t
) {
392 ENSURE(t
->nanoseconds
< NS_PER_S
);
394 return ((isc_uint32_t
)t
->nanoseconds
);
398 isc_time_formattimestamp(const isc_time_t
*t
, char *buf
, unsigned int len
) {
404 now
= (time_t) t
->seconds
;
405 flen
= strftime(buf
, len
, "%d-%b-%Y %X", localtime(&now
));
408 snprintf(buf
+ flen
, len
- flen
,
409 ".%03u", t
->nanoseconds
/ 1000000);
411 snprintf(buf
, len
, "99-Bad-9999 99:99:99.999");
415 isc_time_formathttptimestamp(const isc_time_t
*t
, char *buf
, unsigned int len
) {
422 * 5 spaces, 1 comma, 3 GMT, 2 %d, 4 %Y, 8 %H:%M:%S, 3+ %a, 3+ %b (29+)
424 now
= (time_t)t
->seconds
;
425 flen
= strftime(buf
, len
, "%a, %d %b %Y %H:%M:%S GMT", gmtime(&now
));
430 isc_time_parsehttptimestamp(char *buf
, isc_time_t
*t
) {
435 REQUIRE(buf
!= NULL
);
437 p
= isc_tm_strptime(buf
, "%a, %d %b %Y %H:%M:%S", &t_tm
);
439 return (ISC_R_UNEXPECTED
);
440 when
= isc_tm_timegm(&t_tm
);
442 return (ISC_R_UNEXPECTED
);
443 isc_time_set(t
, when
, 0);
444 return (ISC_R_SUCCESS
);
448 isc_time_formatISO8601(const isc_time_t
*t
, char *buf
, unsigned int len
) {
454 now
= (time_t)t
->seconds
;
455 flen
= strftime(buf
, len
, "%Y-%m-%dT%H:%M:%SZ", gmtime(&now
));