1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
|
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta http-equiv="Content-Language" content="en" />
<title>skalibs: the tai library interface</title>
<meta name="Description" content="skalibs: the tai library interface" />
<meta name="Keywords" content="skalibs c unix tai library libstddjb" />
<!-- <link rel="stylesheet" type="text/css" href="//skarnet.org/default.css" /> -->
</head>
<body>
<p>
<a href="index.html">libstddjb</a><br />
<a href="../libskarnet.html">libskarnet</a><br />
<a href="../index.html">skalibs</a><br />
<a href="//skarnet.org/software/">Software</a><br />
<a href="//skarnet.org/">skarnet.org</a>
</p>
<h1> The <tt>tai</tt> library interface </h1>
<p>
The following functions are declared in the <tt>skalibs/tai.h</tt> header,
and implemented in the <tt>libskarnet.a</tt> or <tt>libskarnet.so</tt> library.
</p>
<h2> General information </h2>
<p>
<tt>tai</tt> is a set of data structures and primitives to represent
and perform operations on time.
</p>
<p>
The point of <tt>tai</tt> is to handle time without ever having to
deal with annoyances such as Y2K, Y2038, NTP limits, non-linear
clocks, and the like. By using the <tt>tai</tt> interface, you ensure
your program will behave properly no matter what.
</p>
<h3> What is the problem ? </h3>
<p>
The standard APIs for time management under Unix are broken in more
or less subtle ways. The most obvious thing is that they do not pass
year 2038. A less obvious problem is that they do not handle leap
seconds correctly. Here are a few references you should read to
understand what is going on:
</p>
<ul>
<li> <a href="https://www.madore.org/~david/misc/time.html">David Madore's page
on time</a>. It's outdated (there was a leap second in 2009), but complete. </li>
<li> From David Madore again, more to the point: a
<a href="https://www.madore.org/~david/computers/unix-leap-seconds.html">page
about leap seconds, UTC and TAI</a>. </li>
<li> The skalibs <a href="../flags.html#clockistai">--enable-tai-clock</a>
documentation. </li>
<li> <a href="https://cr.yp.to/proto/utctai.html">Dan J. Bernstein's page
on UTC, TAI and Unix time</a>. </li>
</ul>
<p>
The meat and potatoes of all this is that programmers cannot simply rely on
standard Unix APIs such as
<a href="https://pubs.opengroup.org/onlinepubs/9699919799/functions/gettimeofday.html">gettimeofday()</a>
(which, by the way, is marked as obsolescent, but it's not going to disappear tomorrow)
to measure time intervals or even to give precise absolute time, and in
any case those APIs will become obsolete in 2038.
</p>
<h3> So what does <tt>tai</tt> do ? </h3>
<p>
<tt>tai</tt> implements - among other things - the
<a href="https://cr.yp.to/libtai/tai64.html">TAI64 and TAI64N</a>
formats, which are used in all of skalibs. This gives a programmer access
to precise <em>linear absolute time</em>, which is suitable for both
timestamping (<em>wallclock</em> usage) and time interval measurements
(<em>stopwatch</em> usage). Additionally, TAI64 passes Y2038 (it can
represent dates exceeding the estimated lifespan of the universe).
</p>
<p>
<tt>tai</tt> has been inspired by Dan J. Bernstein's
<a href="https://cr.yp.to/libtai.html">libtai</a> library, but does not
borrow any code from it.
</p>
<h2> Data structures </h2>
<p>
A <tt>tai_t</tt> structure holds an absolute date with a one-second
precision. A <tt>tain_t</tt> structure holds an absolute date with a
maximum of one-nanosecond precision, as permitted by the underlying system
call. If <a href="../flags.html#usert">flag-usert</a> is clear, the system
clock will be read via
<a href="https://www.opengroup.org/onlinepubs/9699919799/functions/gettimeofday.html">gettimeofday()</a>
system call, which has a one-microsecond precision; if it is set, the
system clock will be read via the
<a href="https://www.opengroup.org/onlinepubs/9699919799/functions/clock_gettime.html">clock_gettime()</a>
system call, which has a one-nanosecond precision. In either case, a current
<tt>tain_t</tt> will be unable to be more precise than the underlying
implementation.
</p>
<p>
A <tt>tai_t</tt>, as well as a <tt>tain_t</tt>, can also
hold a (possibly negative) relative time, i.e. a difference of absolute
dates. It is up to the programmer to make sure that a relative time is
never interpreted as an absolute TAI64 date, and vice-versa.
</p>
<h2> Functions </h2>
<h3> Wallclock operations </h3>
<p>
<code> int tai_now (tai_t *t) </code> <br />
Writes the current time as a TAI value to *<em>t</em>, with a
1-second precision. The current time is based on the system clock.
Make sure skalibs has been compiled with or without the
<a href="../flags.html#clockistai">--enable-tai-clock</a> configure option according
to your system clock synchronization method: skalibs supports a
system clock set to TAI-10 or to UTC.
The function returns 1 if it succeeds, or 0 (and sets errno) if
it fails.
</p>
<p>
<code> int sysclock_get (tain_t *a) </code> <br />
Reads the current value of the system clock (as in CLOCK_REALTIME) into *<em>a</em>.
Returns 1 if it succeeds or 0 (and sets errno) if it fails.
Note that despite being a <tt>tain_t</tt>, *<em>a</em>
<strong>does not contain a TAI value</strong> - it only contains
an internal, Y2038-safe representation of the value of the system
clock, which should be either TAI-10 or UTC. You should not use
this function directly unless you know exactly what you are doing.
</p>
<p>
<code> int sysclock_set (tain_t const *a) </code> <br />
Sets the system clock to *<em>a</em>, provided *<em>a</em> has
the correct internal representation. You should not use this
function directly unless you know exactly what you are doing.
</p>
<p>
<code> int tain_wallclock_read (tain_t *a) </code> <br />
Reads the current time into *<em>a</em>, as a TAI64N value.
Returns 1 if it succeeds or 0 (and sets errno) if it fails.
Here <em>a</em> contains a valid TAI64N stamp, no matter what the
system clock is set to: arithmetic operations can be performed
on it.
</p>
<p>
<code> int tain_setnow (tain_t const *a) </code> <br />
Sets the current time to *<em>a</em>.
Returns 1 if it succeeds or 0 (and sets errno) if it fails.
<em>a</em> must contain a valid TAI64N stamp; proper
operations will be automatically run to convert that stamp into
the right format for the system clock.
</p>
<p>
<code> int tain_now_set_wallclock (tain_t *a) </code> <br />
Tells skalibs that future invocations of <tt>tain_now()</tt>
(see below) should use a wall clock, i.e. the system time
as returned by <tt>clock_gettime(CLOCK_REALTIME)</tt> or
<tt>gettimeofday()</tt>. Also reads the current time into *<em>a</em>.
Returns 1 if it succeeds or 0 (and sets errno) if it fails.
A wall clock is the default: it is not necessary
to call this function before invoking <tt>tain_now()</tt> at the
start of a program.
</p>
<h3> Stopwatch operations </h3>
<p>
The following two operations can only succeed if your system provides the
<a href="https://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_gettime.html">clock_gettime()</a>
primitive with at least one of the CLOCK_MONOTONIC or CLOCK_BOOTTIME clocks.
Otherwise, they will fail with errno set to ENOSYS.
</p>
<p>
<code> int tain_stopwatch_init (tain_t *a, clock_t cl, tain_t *offset) </code> <br />
Initializes a stopwatch in *<em>offset</em>, using a clock named <em>cl</em>.
Typically, <em>cl</em> is something like CLOCK_MONOTONIC, when it is defined
by the system. The actual value of
*<em>offset</em> is meaningless to the user; <em>offset</em>'s only
use is to be given as a second parameter to <tt>tain_stopwatch_read()</tt>.
The function returns 1 if it succeeds or 0 (and sets errno) if it fails.
On success, the current time, as given by the <em>system clock</em> (a
wall clock), is returned in *<em>a</em>.
</p>
<p>
What <tt>tain_stopwatch_init()</tt> does is synchronize the "stopwatch
clock" to the system clock. Right after <tt>tain_stopwatch_init()</tt>
has been called, the absolute times given
by <tt>tain_stopwatch_read()</tt> and <tt>tain_wallclock_read()</tt> are
the same. Then, depending on the accuracy of the system clock, a drift
may appear; calling <tt>tain_stopwatch_init()</tt> again resets that drift
to zero.
</p>
<p>
<code> int tain_stopwatch_read (tain_t *a, clock_t cl, tain_t const *offset) </code> <br />
Gives the absolute time, as a TAI64N value, in *<em>a</em>. This
absolute time is computed as a linear increase (as measured with
the <em>cl</em> clock, which should be a monotonic clock such as
CLOCK_MONOTONIC) since the last time <tt>tain_stopwatch_init()</tt>
was called with parameter <em>offset</em>. <tt>tain_stopwatch_read()</tt>
guarantees precise time interval measurements; however, the time it
gives can slightly differ from the result of <tt>tain_wallclock_read()</tt>.
The function returns 1 if it succeeds or 0 (and sets errno) if it fails.
</p>
<p>
<code> int tain_now_set_stopwatch (tain_t *a) </code> <br />
Tells skalibs that future invocations of <tt>tain_now()</tt>
(see below) should use a stopwatch, i.e. the system time
as returned by <tt>clock_gettime(CLOCK_MONOTONIC)</tt> or similar,
if supported by the system. This is useful when it is more important
for a program to compute unchanging time intervals no matter what the
system clock does, than to display absolute time that is in sync with a
human view of time (which is the cause and reason of most system clock
jumps). <br />
If no monotonic clock is supported by the system, this function does
not change what <tt>tain_now()</tt> refers to (i.e. it will keep
referring to the system clock). <br />
Returns 1 on success and 0 (and sets errno) on failure. On success,
the current time, as given by the <em>system clock</em> (a wall clock),
is returned in *<em>a</em>.
</p>
<h3> All-purpose time reading </h3>
<p>
<code> int tain_now (tain_t *a) </code> <br />
Writes the current time, as a TAI value, to *<em>a</em>. This is the
function you should use by default. It returns 1 if it succeeds or
0 (and sets errno) if it fails.
</p>
<p>
<tt>tain_now()</tt> relies on the concept that there is One True Time Source
for the process, and that is where it reads time from. By default, the
One True Time Source is the system clock (a wall clock), and <tt>tain_now()</tt>
is actually an alias to <tt>tain_wallclock_read()</tt>. At the start of a
program, calling <tt>tain_now_set_stopwatch()</tt> will define a monotonic
clock (if supported by the system) as the One True Time Source, which will
make <tt>tain_now()</tt> resistant to system clock jumps, but will also
make it unsuitable for timestamping.
</p>
<p>
In other words: the <em>first</em> time you need to read the clock, or
at the start of your program, you should use
<tt>tain_now_set_wallclock()</tt> or <tt>tain_now_set_stopwatch()</tt>
depending on whether you want the One True Time Source to be the system
clock (CLOCK_REALTIME or <tt>gettimeofday()</tt>) or a stopwatch
(CLOCK_MONOTONIC, if supported). Afterwards, every time you need to read
from that time source, use <tt>tain_now()</tt>. skalibs functions that
may block, such as <tt>iopause_g</tt>, internally call <tt>tain_now()</tt>
to update the timestamp they're using, so they will use the time source
you have defined. (Functions ending in <tt>_g</tt>
use the STAMP global variable to store the current timestamp.)
</p>
<h3> Converting to/from libc representations </h3>
<p>
The following functions only convert from a certain structure
format to another; they do not make any assumption about the
format of the time contained in those structures. For instance,
for the <tt>tai_from_timeval</tt> function, if the struct timeval
contains an absolute UTC time, then the tai_t will also contain
the same UTC time. Despite being a tai_t, it may contain
something else than TAI time.
</p>
<p>
If you need conversion from the native machine
system clock format to TAI, see the next section.
</p>
<p>
<code> int tai_from_time (tai_t *t, time_t u) <br />
int tai_relative_from_time (tai_t *t, time_t u) </code> <br />
Those functions convert an absolute (resp. relative) time in a
time_t to an absolute (resp. relative)
time in a tai_t, with a 1-second precision. They return 1,
unless the time_t value is invalid (in which case they return 0).
</p>
<p>
<code> int time_from_tai (time_t *u, tai_t const *t) <br />
int time_from_tai_relative (time_t *u, tai_t const *t) </code> <br />
The inverse functions of the previous ones. Be aware that
time_t is 32 bits on some systems and cannot store all values
of a tai_t (in which case the functions will return 0 EOVERFLOW).
</p>
<p>
<code> int tain_from_timeval (tain_t *a, struct timeval const *tv) <br />
int tain_relative_from_timeval (tain_t *a, struct timeval const *tv) <br />
int tain_from_timespec (tain_t *a, struct timespec const *ts) <br />
int tain_relative_from_timespec (tain_t *a, struct timespec const *ts) <br />
int timeval_from_tain (struct timeval *tv, tain_t const *a) <br />
int timeval_from_tain_relative (struct timeval *tv, tain_t const *a) <br />
int timespec_from_tain (struct timespec *ts, tain_t const *a) <br />
int timespec_from_tain_relative (struct timespec *ts, tain_t const *a) </code> <br />
Same conversion operations, between <tt>tain_t</tt> and a
<tt>struct timeval</tt> or <tt>struct timespec</tt>. The 1-microsecond
(for <tt>struct timeval</tt>) or 1-nanosecond (for <tt>struct timespec</tt>)
precision is preserved.
</p>
<h3> Conversion between TAI and the system clock format </h3>
<p>
Unlike the previous functions, the functions listed here will
always operate on valid absolute timestamps. Only TAI64 time is
stored in tai_t structures, and only TAI64N time is stored in
tain_t structures. These functions will convert to/from TAI,
from/to the machine system clock format, i.e. TAI-10 or UTC
depending on whether skalibs was
compiled with the --enable-tai-clock configure option).
This is useful to get valid TAI/TAI64N timestamps out of
information exported by the system, for instance the time_t
returned by <a href="https://pubs.opengroup.org/onlinepubs/9699919799/functions/time.html">time()</a>,
or in the <tt>st_atim</tt>, <tt>st_mtim</tt> or
<tt>st_ctim</tt> fields of a <tt>struct stat</tt>.
</p>
<p>
The functions return 1 in case of success, or 0 if the conversion
could not be performed; in which case errno is set to EINVAL if
the input argument was not a valid timestamp, to EOVERFLOW if the
output could not be represented in the chosen format (which may
happen on systems with a 32 bit <tt>time_t</tt>), or other error
codes.
</p>
<code> int tai_from_time_sysclock (tai_t *a, time_t t) <br />
int time_sysclock_from_tai (time_t *t, tai_t const *a) <br />
int tain_from_timeval_sysclock (tain_t *a, struct timeval const *tv) <br />
int timeval_sysclock_from_tain (struct timeval *tv, tain_t const *a) <br />
int tain_from_timespec_sysclock (tain_t *a, struct timespec const *ts) <br />
int timespec_sysclock_from_tain (struct timespec *ts, tain_t const *a) </code>
<h3> Conversions to/from basic types </h3>
<p>
<code> int tain_uint (tain_t *a, unsigned int c) </code> <br />
Stores a relative time of <em>c</em> seconds into <em>a</em>.
Normally returns 1, but may return 0 EINVAL on pathological numbers.
</p>
<p>
<code> int tain_from_millisecs (tain_t *a, int ms) </code> <br />
This function makes a <tt>tain_t</tt> representing a relative
time of <em>ms</em> milliseconds. <em>ms</em> must be non-negative.
The function returns 1, unless <em>ms</em> is negative, in which case
it returns 0 EINVAL.
</p>
<p>
<code> int tain_to_millisecs (tain_t const *a) </code> <br />
If *<em>a</em> contains a non-negative relative time that fits into
a 31-bit integer number of milliseconds, the function returns that
number. Else it returns -1 EINVAL.
</p>
<h3> Time computations </h3>
<p>
<code> int tai_add (tai_t *t, tai_t const *t1, tai_t const *t2) </code> <br />
Stores *<em>t1</em> + *<em>t2</em> into <em>t</em>. Of course, *<em>t1</em>
and *<em>t2</em> must not both represent absolute times.
The function normally returns 1, but will return 0 on bad inputs.
</p>
<p>
<code> int tai_sub (tai_t *t, tai_t const *t1, tai_t const *t2) </code> <br />
Stores *<em>t1</em> - *<em>t2</em> into <em>t</em>. *<em>t1</em> cannot
be relative if *<em>t2</em> is absolute. If they are both relative or
both absolute, then *<em>t</em> is relative, else it's absolute.
The function normally returns 1, but will return 0 on bad inputs.
</p>
<p>
<code> int tain_add (tain_t *a, tain_t const *a1, tain_t const *a2) <br />
int tain_sub (tain_t *a, tain_t const *a1, tain_t const *a2) </code> <br />
Same thing with <tt>tain_t</tt>.
</p>
<p>
<code> int tain_addsec (tain_t *a, tain_t const *a1, int c) </code> <br />
Adds <em>c</em> seconds to *<em>a1</em> and stores the result into <em>a</em>.
<em>c</em> may be negative.
</p>
<p>
<code> void tain_half (tain_t *a, tain_t const *b) </code> <br />
Stores *<em>b</em>/2 into <em>a</em>. *<em>b</em> must be relative.
</p>
<h3> Comparing dates or durations </h3>
<p>
<code> int tai_less (tai_t const *t1, tai_t const *t2) <br />
int tain_less (tain_t const *t1, tain_t const *t2) </code> <br />
Those functions return nonzero iff *<em>t1</em> is lesser than *<em>t2</em>.
*<em>t1</em> and *<em>t2</em> must be both relative, or both absolute.
</p>
<h3> Packing and unpacking </h3>
<p>
<code> void tai_pack (char *s, tai_t const *t) </code> <br />
Marshals *<em>t</em> into the buffer <em>s</em> points to, which
must be preallocated with at least TAI_PACK (8) characters. Afterwards,
the buffer contains the
<a href="https://cr.yp.to/libtai/tai64.html#tai64">external TAI64 format</a>
representation of *<em>t</em>.
</p>
<p>
<code> void tai_unpack (char const *s, tai_t *t) </code> <br />
Unmarshals the
<a href="https://cr.yp.to/libtai/tai64.html#tai64">external TAI64 format</a>
label pointed to by <em>s</em> (at least TAI_PACK characters) and stores
the result into <em>t</em>.
</p>
<p>
<code> void tain_pack (char *s, tain_t const *a) <br />
void tain_unpack (char const *s, tain_t *a) </code> <br />
Same thing with
<a href="https://cr.yp.to/libtai/tai64.html#tai64n">external TAI64N format</a>,
using TAIN_PACK (12) characters.
</p>
<h3> Formatting and scanning </h3>
<p>
<code> unsigned int tain_fmt (char *s, tain_t const *a) </code> <br />
Writes into <em>s</em> an ASCII representation of *<em>a</em> in external
TAI64N format. <em>s</em> must point to a preallocated buffer of at least
TAIN_PACK*2 (24) characters. The function returns the number of bytes that
have been written to <em>s</em> (24).
</p>
<p>
<code> unsigned int tain_scan (char const *s, tain_t *a) </code> <br />
Reads 24 characters from <em>s</em>; if those characters are a valid ASCII
representation of the external TAI64N format of some time value, this value
is stored into <em>a</em>, and 24 is returned. Else 0 is returned.
</p>
<a name="timestamp"><h3> Timestamping </h3></a>
<p>
A <em>TAI64N timestamp</em> is a string of 25 characters: a single '@'
character followed by the ASCII representation of the TAI64N external
format of an absolute date.
</p>
<p>
<code> unsigned int timestamp_fmt (char *s, tain_t const *a) </code> <br />
Writes a TAI64N timestamp representing the absolute date *<em>a</em>
into the 25 characters pointed to by <em>s</em>. Returns 25.
</p>
<p>
<code> unsigned int timestamp_scan (char const *s, tain_t *a) </code> <br />
Reads 25 characters at <em>s</em>. If those characters are a valid TAI64N
timestamp, stores the absolute date in <em>a</em> and returns 25. Else,
returns 0.
</p>
<p>
<code> int timestamp (char *s) </code> <br />
Writes the current time (read from the system clock) as a TAI64N timestamp
into <em>s</em>. Returns 1 if it succeeds or 0 (and sets errno) if it fails.
</p>
<p>
TAI64N timestamps are an efficient, robust, and easy-to-use way of
timestampping log lines. They're easy to recognize in automatic data
parsers. Log files where every line starts with a TAI64N timestamp can
be merged and alphanumerically sorted: the resulting file will be
chronologically sorted.
</p>
<p>
The <a href="//skarnet.org/software/s6/">s6</a> package
provides tools to convert TAI64N timestamps into human-readable
dates. Please do not embed human-readable dates in your log files,
thus making parsing tools unnecessarily hard to write;
use TAI64N timestamps instead, design tools that can parse them,
and translate them to human-readable form at human analysis time.
</p>
</body>
</html>
|