1 /*
2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3  *
4  * SPDX-License-Identifier: MPL-2.0
5  *
6  * This Source Code Form is subject to the terms of the Mozilla Public
7  * License, v. 2.0.  If a copy of the MPL was not distributed with this
8  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
9  *
10  * See the COPYRIGHT file distributed with this work for additional
11  * information regarding copyright ownership.
12  */
13 
14 #ifndef ISC_TIME_H
15 #define ISC_TIME_H 1
16 
17 #include <errno.h>
18 #include <inttypes.h>
19 #include <stdbool.h>
20 #include <time.h>
21 #include <windows.h>
22 
23 #include <isc/lang.h>
24 #include <isc/types.h>
25 
26 /***
27  *** POSIX Shims
28  ***/
29 
30 struct tm *
31 gmtime_r(const time_t *clock, struct tm *result);
32 
33 struct tm *
34 localtime_r(const time_t *clock, struct tm *result);
35 
36 int
37 nanosleep(const struct timespec *req, struct timespec *rem);
38 
39 typedef uint32_t useconds_t;
40 
41 int
42 usleep(useconds_t usec);
43 
44 /***
45  *** Intervals
46  ***/
47 
48 /*
49  * The contents of this structure are private, and MUST NOT be accessed
50  * directly by callers.
51  *
52  * The contents are exposed only to allow callers to avoid dynamic allocation.
53  */
54 struct isc_interval {
55 	int64_t interval;
56 };
57 
58 LIBISC_EXTERNAL_DATA extern const isc_interval_t *const isc_interval_zero;
59 
60 /*
61  * ISC_FORMATHTTPTIMESTAMP_SIZE needs to be 30 in C locale and potentially
62  * more for other locales to handle longer national abbreviations when
63  * expanding strftime's %a and %b.
64  */
65 #define ISC_FORMATHTTPTIMESTAMP_SIZE 50
66 
67 ISC_LANG_BEGINDECLS
68 
69 void
70 isc_interval_set(isc_interval_t *i, unsigned int seconds,
71 		 unsigned int nanoseconds);
72 /*
73  * Set 'i' to a value representing an interval of 'seconds' seconds and
74  * 'nanoseconds' nanoseconds, suitable for use in isc_time_add() and
75  * isc_time_subtract().
76  *
77  * Requires:
78  *
79  *	't' is a valid pointer.
80  *	nanoseconds < 1000000000.
81  */
82 
83 bool
84 isc_interval_iszero(const isc_interval_t *i);
85 /*
86  * Returns true iff. 'i' is the zero interval.
87  *
88  * Requires:
89  *
90  *	'i' is a valid pointer.
91  */
92 
93 /***
94  *** Absolute Times
95  ***/
96 
97 /*
98  * The contents of this structure are private, and MUST NOT be accessed
99  * directly by callers.
100  *
101  * The contents are exposed only to allow callers to avoid dynamic allocation.
102  */
103 
104 struct isc_time {
105 	FILETIME absolute;
106 };
107 
108 LIBISC_EXTERNAL_DATA extern const isc_time_t *const isc_time_epoch;
109 
110 void
111 isc_time_set(isc_time_t *t, unsigned int seconds, unsigned int nanoseconds);
112 /*%<
113  * Set 't' to a value which represents the given number of seconds and
114  * nanoseconds since 00:00:00 January 1, 1970, UTC.
115  *
116  * Requires:
117  *\li   't' is a valid pointer.
118  *\li   nanoseconds < 1000000000.
119  */
120 
121 void
122 isc_time_settoepoch(isc_time_t *t);
123 /*
124  * Set 't' to the time of the epoch.
125  *
126  * Notes:
127  * 	The date of the epoch is platform-dependent.
128  *
129  * Requires:
130  *
131  *	't' is a valid pointer.
132  */
133 
134 bool
135 isc_time_isepoch(const isc_time_t *t);
136 /*
137  * Returns true iff. 't' is the epoch ("time zero").
138  *
139  * Requires:
140  *
141  *	't' is a valid pointer.
142  */
143 
144 isc_result_t
145 isc_time_now(isc_time_t *t);
146 /*
147  * Set 't' to the current absolute time.
148  *
149  * Requires:
150  *
151  *	't' is a valid pointer.
152  *
153  * Returns:
154  *
155  *	Success
156  *	Unexpected error
157  *		Getting the time from the system failed.
158  *	Out of range
159  *		The time from the system is too large to be represented
160  *		in the current definition of isc_time_t.
161  */
162 
163 isc_result_t
164 isc_time_now_hires(isc_time_t *t);
165 /*%<
166  * Set 't' to the current absolute time. Uses higher resolution clocks
167  * recommended when microsecond accuracy is required.
168  *
169  * Requires:
170  *
171  *\li	't' is a valid pointer.
172  *
173  * Returns:
174  *
175  *\li	Success
176  *\li	Unexpected error
177  *		Getting the time from the system failed.
178  *\li	Out of range
179  *		The time from the system is too large to be represented
180  *		in the current definition of isc_time_t.
181  */
182 
183 isc_result_t
184 isc_time_nowplusinterval(isc_time_t *t, const isc_interval_t *i);
185 /*
186  * Set *t to the current absolute time + i.
187  *
188  * Note:
189  *	This call is equivalent to:
190  *
191  *		isc_time_now(t);
192  *		isc_time_add(t, i, t);
193  *
194  * Requires:
195  *
196  *	't' and 'i' are valid pointers.
197  *
198  * Returns:
199  *
200  *	Success
201  *	Unexpected error
202  *		Getting the time from the system failed.
203  *	Out of range
204  *		The interval added to the time from the system is too large to
205  *		be represented in the current definition of isc_time_t.
206  */
207 
208 int
209 isc_time_compare(const isc_time_t *t1, const isc_time_t *t2);
210 /*
211  * Compare the times referenced by 't1' and 't2'
212  *
213  * Requires:
214  *
215  *	't1' and 't2' are valid pointers.
216  *
217  * Returns:
218  *
219  *	-1		t1 < t2		(comparing times, not pointers)
220  *	0		t1 = t2
221  *	1		t1 > t2
222  */
223 
224 isc_result_t
225 isc_time_add(const isc_time_t *t, const isc_interval_t *i, isc_time_t *result);
226 /*
227  * Add 'i' to 't', storing the result in 'result'.
228  *
229  * Requires:
230  *
231  *	't', 'i', and 'result' are valid pointers.
232  *
233  * Returns:
234  * 	Success
235  *	Out of range
236  * 		The interval added to the time is too large to
237  *		be represented in the current definition of isc_time_t.
238  */
239 
240 isc_result_t
241 isc_time_subtract(const isc_time_t *t, const isc_interval_t *i,
242 		  isc_time_t *result);
243 /*
244  * Subtract 'i' from 't', storing the result in 'result'.
245  *
246  * Requires:
247  *
248  *	't', 'i', and 'result' are valid pointers.
249  *
250  * Returns:
251  *	Success
252  *	Out of range
253  *		The interval is larger than the time since the epoch.
254  */
255 
256 uint64_t
257 isc_time_microdiff(const isc_time_t *t1, const isc_time_t *t2);
258 /*
259  * Find the difference in milliseconds between time t1 and time t2.
260  * t2 is the subtrahend of t1; ie, difference = t1 - t2.
261  *
262  * Requires:
263  *
264  *	't1' and 't2' are valid pointers.
265  *
266  * Returns:
267  *	The difference of t1 - t2, or 0 if t1 <= t2.
268  */
269 
270 isc_result_t
271 isc_time_parsehttptimestamp(char *input, isc_time_t *t);
272 /*%<
273  * Parse the time in 'input' into the isc_time_t pointed to by 't',
274  * expecting a format like "Mon, 30 Aug 2000 04:06:47 GMT"
275  *
276  *  Requires:
277  *\li      'buf' and 't' are not NULL.
278  */
279 
280 uint32_t
281 isc_time_nanoseconds(const isc_time_t *t);
282 /*
283  * Return the number of nanoseconds stored in a time structure.
284  *
285  * Notes:
286  *	This is the number of nanoseconds in excess of the number
287  *	of seconds since the epoch; it will always be less than one
288  *	full second.
289  *
290  * Requires:
291  *	't' is a valid pointer.
292  *
293  * Ensures:
294  *	The returned value is less than 1*10^9.
295  */
296 
297 void
298 isc_time_formattimestamp(const isc_time_t *t, char *buf, unsigned int len);
299 /*
300  * Format the time 't' into the buffer 'buf' of length 'len',
301  * using a format like "30-Aug-2000 04:06:47.997" and the local time zone.
302  * If the text does not fit in the buffer, the result is indeterminate,
303  * but is always guaranteed to be null terminated.
304  *
305  *  Requires:
306  *      'len' > 0
307  *      'buf' points to an array of at least len chars
308  *
309  */
310 
311 void
312 isc_time_formathttptimestamp(const isc_time_t *t, char *buf, unsigned int len);
313 /*
314  * Format the time 't' into the buffer 'buf' of length 'len',
315  * using a format like "Mon, 30 Aug 2000 04:06:47 GMT"
316  * If the text does not fit in the buffer, the result is indeterminate,
317  * but is always guaranteed to be null terminated.
318  *
319  *  Requires:
320  *      'len' > 0
321  *      'buf' points to an array of at least len chars
322  *
323  */
324 
325 isc_result_t
326 isc_time_parsehttptimestamp(char *input, isc_time_t *t);
327 /*%<
328  * Parse the time in 'input' into the isc_time_t pointed to by 't',
329  * expecting a format like "Mon, 30 Aug 2000 04:06:47 GMT"
330  *
331  *  Requires:
332  *\li      'buf' and 't' are not NULL.
333  */
334 
335 void
336 isc_time_formatISO8601L(const isc_time_t *t, char *buf, unsigned int len);
337 /*%<
338  * Format the time 't' into the buffer 'buf' of length 'len',
339  * using the ISO8601 format: "yyyy-mm-ddThh:mm:ss"
340  * If the text does not fit in the buffer, the result is indeterminate,
341  * but is always guaranteed to be null terminated.
342  *
343  *  Requires:
344  *\li      'len' > 0
345  *\li      'buf' points to an array of at least len chars
346  *
347  */
348 
349 void
350 isc_time_formatISO8601Lms(const isc_time_t *t, char *buf, unsigned int len);
351 /*%<
352  * Format the time 't' into the buffer 'buf' of length 'len',
353  * using the ISO8601 format: "yyyy-mm-ddThh:mm:ss.sss"
354  * If the text does not fit in the buffer, the result is indeterminate,
355  * but is always guaranteed to be null terminated.
356  *
357  *  Requires:
358  *\li      'len' > 0
359  *\li      'buf' points to an array of at least len chars
360  *
361  */
362 
363 void
364 isc_time_formatISO8601Lus(const isc_time_t *t, char *buf, unsigned int len);
365 /*%<
366  * Format the time 't' into the buffer 'buf' of length 'len',
367  * using the ISO8601 format: "yyyy-mm-ddThh:mm:ss.ssssss"
368  * If the text does not fit in the buffer, the result is indeterminate,
369  * but is always guaranteed to be null terminated.
370  *
371  *  Requires:
372  *\li      'len' > 0
373  *\li      'buf' points to an array of at least len chars
374  *
375  */
376 
377 void
378 isc_time_formatISO8601(const isc_time_t *t, char *buf, unsigned int len);
379 /*%<
380  * Format the time 't' into the buffer 'buf' of length 'len',
381  * using the ISO8601 format: "yyyy-mm-ddThh:mm:ssZ"
382  * If the text does not fit in the buffer, the result is indeterminate,
383  * but is always guaranteed to be null terminated.
384  *
385  *  Requires:
386  *\li      'len' > 0
387  *\li      'buf' points to an array of at least len chars
388  *
389  */
390 
391 void
392 isc_time_formatISO8601ms(const isc_time_t *t, char *buf, unsigned int len);
393 /*%<
394  * Format the time 't' into the buffer 'buf' of length 'len',
395  * using the ISO8601 format: "yyyy-mm-ddThh:mm:ss.sssZ"
396  * If the text does not fit in the buffer, the result is indeterminate,
397  * but is always guaranteed to be null terminated.
398  *
399  *  Requires:
400  *\li      'len' > 0
401  *\li      'buf' points to an array of at least len chars
402  *
403  */
404 
405 void
406 isc_time_formatISO8601us(const isc_time_t *t, char *buf, unsigned int len);
407 /*%<
408  * Format the time 't' into the buffer 'buf' of length 'len',
409  * using the ISO8601 format: "yyyy-mm-ddThh:mm:ss.ssssssZ"
410  * If the text does not fit in the buffer, the result is indeterminate,
411  * but is always guaranteed to be null terminated.
412  *
413  *  Requires:
414  *\li      'len' > 0
415  *\li      'buf' points to an array of at least len chars
416  *
417  */
418 
419 void
420 isc_time_formatshorttimestamp(const isc_time_t *t, char *buf, unsigned int len);
421 /*%<
422  * Format the time 't' into the buffer 'buf' of length 'len',
423  * using the format "yyyymmddhhmmsssss" useful for file timestamping.
424  * If the text does not fit in the buffer, the result is indeterminate,
425  * but is always guaranteed to be null terminated.
426  *
427  *  Requires:
428  *\li      'len' > 0
429  *\li      'buf' points to an array of at least len chars
430  *
431  */
432 
433 uint32_t
434 isc_time_seconds(const isc_time_t *t);
435 /*%<
436  * Return the number of seconds since the epoch stored in a time structure.
437  *
438  * Requires:
439  *
440  *\li	't' is a valid pointer.
441  */
442 
443 isc_result_t
444 isc_time_secondsastimet(const isc_time_t *t, time_t *secondsp);
445 /*%<
446  * Ensure the number of seconds in an isc_time_t is representable by a time_t.
447  *
448  * Notes:
449  *\li	The number of seconds stored in an isc_time_t might be larger
450  *	than the number of seconds a time_t is able to handle.  Since
451  *	time_t is mostly opaque according to the ANSI/ISO standard
452  *	(essentially, all you can be sure of is that it is an arithmetic type,
453  *	not even necessarily integral), it can be tricky to ensure that
454  *	the isc_time_t is in the range a time_t can handle.  Use this
455  *	function in place of isc_time_seconds() any time you need to set a
456  *	time_t from an isc_time_t.
457  *
458  * Requires:
459  *\li	't' is a valid pointer.
460  *
461  * Returns:
462  *\li	Success
463  *\li	Out of range
464  */
465 
466 ISC_LANG_ENDDECLS
467 
468 #endif /* ISC_TIME_H */
469