File Coverage

lib/Time/TAI/Simple.pm
Criterion Covered Total %
statement 90 127 70.8
branch 23 48 47.9
condition 5 11 45.4
subroutine 17 18 94.4
pod 8 9 88.8
total 143 213 67.1


line stmt bran cond sub pod time code
1             package Time::TAI::Simple;
2              
3             # ABSTRACT: Easily obtain current TAI time, using UNIX epoch.
4              
5 2     2   242043 use strict;
  2         16  
  2         55  
6 2     2   10 use warnings;
  2         3  
  2         58  
7             require v5.10.0;
8              
9 2     2   918 use POSIX::RT::Clock;
  2         2209  
  2         58  
10 2     2   13 use Time::HiRes;
  2         4  
  2         11  
11 2     2   1483 use HTTP::Tiny;
  2         98112  
  2         91  
12              
13 2     2   16 use base qw(Exporter);
  2         4  
  2         208  
14              
15             BEGIN {
16 2     2   9 @Time::TAI::Simple::EXPORT = qw(tai tai10 tai35);
17 2         3278 $Time::TAI::Simple::VERSION = '1.15';
18             }
19              
20             our @LEAPSECOND_UNIX_PATHNAME_LIST = (
21             '/etc/leap-seconds.list',
22             ($ENV{'HOME'} // '/root') . "/.leap-seconds.list",
23             "/var/tmp/leap-seconds.list",
24             "/tmp/leap-seconds.list"
25             );
26              
27             our @LEAPSECOND_WINDOWS_PATHNAME_LIST = (
28             ($ENV{'WINDIR'} // 'C:\WINDOWS') . '\leap-seconds.list',
29             ($ENV{'HOMEDRIVE'} // 'C:') . ($ENV{'HOMEPATH'} // '\Users') . '\.leap-seconds.list',
30             ($ENV{'TEMP'} // 'C:\TEMPDIR') . '\leap-seconds.list'
31             );
32              
33             our $LEAPSECOND_IETF_DELTA = 2208960000; # difference between IETF's leapseconds (since 1900-01-01 00:00:00) and equivalent UNIX epoch time.
34              
35             our @FALLBACK_LEAPSECONDS_LIST = ( # from https://www.ietf.org/timezones/data/leap-seconds.list
36             [2272060800, 10],
37             [2287785600, 11],
38             [2303683200, 12],
39             [2335219200, 13],
40             [2366755200, 14],
41             [2398291200, 15],
42             [2429913600, 16],
43             [2461449600, 17],
44             [2492985600, 18],
45             [2524521600, 19],
46             [2571782400, 20],
47             [2603318400, 21],
48             [2634854400, 22],
49             [2698012800, 23],
50             [2776982400, 24],
51             [2840140800, 25],
52             [2871676800, 26],
53             [2918937600, 27],
54             [2950473600, 28],
55             [2982009600, 29],
56             [3029443200, 30],
57             [3076704000, 31],
58             [3124137600, 32],
59             [3345062400, 33],
60             [3439756800, 34],
61             [3550089600, 35],
62             [3644697600, 36],
63             [3692217600, 37]
64             );
65              
66             our $TAI_OR = undef;
67             our $TAI10_OR = undef;
68             our $TAI35_OR = undef;
69              
70             sub new {
71 2004     2004 1 8014 my ($class, %opt_hr) = @_;
72 2004         2289 my $success = 0;
73 2004         2010 my $timer = undef;
74 2004         2106 eval { $timer = POSIX::RT::Clock->new('monotonic'); $success = 1; };
  2004         3778  
  2004         2319  
75 2004 50       2855 return undef unless ($success);
76              
77 2004         7329 my $self = {
78             opt_hr => \%opt_hr,
79             tm_or => undef, # POSIX::RT::Clock instance, for monotonic clock access.
80             ls_ar => [], # list of leap seconds, as tuples of [UTC epoch, $nsec].
81             ls_tm => 0, # epoch mtime of leap seconds list, so we know when it needs updating.
82             dl_tm => 0, # epoch time we last tried to download a new leapsecond list.
83             tm_base => 0.0, # add to monotonic clock time to get TAI epoch time.
84             mode => 'tai10', # one of: "tai", "tai10", or "tai35".
85             dl_fr => undef,
86             dl_to => undef
87             };
88 2004         2710 bless ($self, $class);
89 2004         3649 $self->{http_or} = HTTP::Tiny->new(max_redirect => 15, agent => 'Wget/1.18 (linux-gnu)');
90 2004         110201 $self->{mode} = $self->opt('mode', 'tai10');
91 2004 50       2601 $self->download_leapseconds() if ($self->opt('download_leapseconds', 0));
92 2004 100       2619 $self->load_leapseconds() unless ($self->opt('do_not_load_leapseconds'));
93 2004         3313 $self->calculate_base(); # also sets tm_or and potentially ls_next
94 2004         7547 return $self;
95             }
96              
97             sub time {
98 3     3 1 11 return $_[0]->{tm_or}->get_time() + $_[0]->{tm_base};
99             }
100              
101             sub tai {
102 1 50   1 1 10 $TAI_OR = Time::TAI::Simple->new(mode => 'tai') unless (defined($TAI_OR));
103 1         3 return $TAI_OR->time();
104             }
105              
106             sub tai10 {
107 1 50   1 1 12 $TAI10_OR = Time::TAI::Simple->new(mode => 'tai10') unless (defined($TAI10_OR));
108 1         4 return $TAI10_OR->time();
109             }
110              
111             sub tai35 {
112 1 50   1 1 526 $TAI35_OR = Time::TAI::Simple->new(mode => 'tai35') unless (defined($TAI35_OR));
113 1         3 return $TAI35_OR->time();
114             }
115              
116             sub calculate_base {
117 2004     2004 1 2308 my ($self, %opt_h) = @_;
118 2004 50       5105 $self->{tm_or} = POSIX::RT::Clock->new('monotonic') unless (defined($self->{tm_or}));
119 2004 50       3132 if (defined($self->opt('base_time', undef, \%opt_h))) {
120 0         0 $self->{tm_base} = $self->opt('base_time', undef, \%opt_h);
121 0         0 return;
122             }
123 2004         3182 my $tm = Time::HiRes::time();
124 2004         3232 my $mo = $self->{tm_or}->get_time();
125 2004         2037 my $delta = 0;
126 2004         3387 for (my $ix = 0; defined($self->{ls_ar}->[$ix]); $ix++) {
127 112         100 my ($ls_tm, $ls_delta) = @{$self->{ls_ar}->[$ix]};
  112         143  
128 112 50       218 if ($ls_tm > $tm - $delta) {
129 0         0 $self->{ls_next} = $ix;
130 0         0 last;
131             }
132 112         160 $delta = $ls_delta;
133             }
134 2004 100       3089 $delta -= 10 if ($self->{mode} eq 'tai10');
135 2004 100       2693 $delta -= 35 if ($self->{mode} eq 'tai35');
136 2004 100       2584 $delta -= $self->_fine_tune() if ($self->opt('fine_tune', 1));
137 2004         3023 $self->{tm_base} = $tm - $mo - $delta;
138 2004         2429 return;
139             }
140              
141             sub load_leapseconds {
142 4     4 1 16 my ($self, %opt_h) = @_;
143 4         8 my $filename = $self->_leapseconds_filename(\%opt_h);
144 4         8 my $fh = undef;
145 4         9 $self->{ls_ar} = [];
146 4 50       69 if (open($fh, '<', $filename)) {
147 0         0 while(defined(my $x = <$fh>)) {
148 0 0       0 next unless ($x =~ /^(\d{10})\s+(\d{2})/);
149 0         0 my ($iers_tm, $nsec) = ($1, $2);
150 0         0 my $epoch_tm = $iers_tm - $LEAPSECOND_IETF_DELTA;
151 0         0 push(@{$self->{ls_ar}}, [$epoch_tm, $nsec]);
  0         0  
152             # can't set ls_next here, because base tai time hasn't been computed yet.
153             }
154 0         0 close($fh);
155 0         0 $self->{ls_tm} = (stat($filename))[9];
156             } else {
157 4         13 foreach my $tup (@FALLBACK_LEAPSECONDS_LIST) {
158 112         112 my ($iers_tm, $nsec) = @{$tup};
  112         136  
159 112         116 my $epoch_tm = $iers_tm - $LEAPSECOND_IETF_DELTA;
160 112         98 push(@{$self->{ls_ar}}, [$epoch_tm, $nsec]);
  112         216  
161             }
162 4         6 $self->{ls_tm} = CORE::time();
163             }
164 4         15 return 1;
165             }
166              
167             sub download_leapseconds {
168 0     0 1 0 my ($self, %opt_h) = @_;
169 0         0 my $response = 0;
170 0         0 my @url_list = ();
171 0         0 $self->{dl_tm} = CORE::time();
172 0 0       0 if (defined(my $urls = $self->opt('download_urls', undef, \%opt_h))) {
173 0 0       0 if (ref($urls) eq 'ARRAY') {
    0          
174 0         0 push(@url_list, @{$urls});
  0         0  
175             }
176             elsif ($urls =~ /^(http:|ftp:|file:)/i) {
177 0         0 push(@url_list, $urls);
178             }
179             }
180 0         0 push (@url_list, 'http://www.ciar.org/ttk/codecloset/leap-seconds.list');
181 0         0 push (@url_list, 'https://www.ietf.org/timezones/data/leap-seconds.list');
182 0         0 eval {
183 0         0 my $http_or = $self->{http_or};
184 0         0 my $leapseconds_filename = $self->_leapseconds_filename(\%opt_h);
185 0         0 foreach my $url (@url_list) {
186 0         0 my $reply = $http_or->mirror($url, $leapseconds_filename, {});
187 0 0 0     0 next unless (defined($reply) && $reply->{success});
188 0         0 $response = 1;
189 0         0 $self->{dl_fr} = $url;
190 0         0 $self->{dl_to} = $leapseconds_filename;
191 0         0 last;
192             }
193             };
194 0         0 return $response;
195             }
196              
197             sub opt {
198 10024     10024 0 12776 my ($self, $name, $default_value, $alt_hr) = @_;
199 10024 100       17731 return $self->{opt_hr}->{$name} if (defined($self->{opt_hr}->{$name}));
200 7021 50 66     14703 return $alt_hr->{$name} if (defined($alt_hr) && ref($alt_hr) eq 'HASH' && defined($alt_hr->{$name}));
      66        
201 7021         11695 return $default_value;
202             }
203              
204             sub _fine_tune {
205 1004     1004   1208 my $self = shift(@_);
206 1004         923 my $sum = 0;
207 1004         1540 for (my $i = 0; $i < 100; $i++ ) {
208 100400         180758 $sum += 0 - Time::HiRes::time() + Time::HiRes::time();
209             }
210 1004         1229 my $jitter = $sum * 0.17; # Correct for v5.18.1, need to test others for skew.
211             # printf ('jitter=%0.010f'."\n", $jitter);
212 1004         1457 return $jitter;
213             }
214              
215             sub _leapseconds_filename {
216 4     4   6 my($self, $opt_hr) = @_;
217 4   50     9 $opt_hr //= {};
218 4         6 my $pathname = $self->opt('leapseconds_pathname', undef, $opt_hr);
219 4 50       9 return $pathname if (defined($pathname));
220 4 50       13 if ($^O eq 'MSWin32') {
221 0         0 foreach my $f (@LEAPSECOND_WINDOWS_PATHNAME_LIST) {
222 0         0 $pathname = $f;
223 0 0       0 return $f if (-e $f);
224             }
225             } else {
226 4         6 foreach my $f (@LEAPSECOND_UNIX_PATHNAME_LIST) {
227 16         29 $pathname = $f;
228 16 50       1158 return $f if (-e $f);
229             }
230             }
231 4         14 return $pathname;
232             }
233              
234             1;
235              
236             =head1 NAME
237              
238             Time::TAI::Simple - High resolution UNIX epoch time without leapseconds
239              
240             =head1 VERSION
241              
242             1.13
243              
244             =head1 SYNOPSIS
245              
246             use Time::TAI::Simple; # imports tai, tai10, and tai35
247              
248             # simple and fast procedural interface:
249              
250             $seconds_since_epoch = tai();
251             $since_epoch_minus_ten = tai10(); # Probably what you want!
252             $close_to_utc_time_for_now = tai35();
253              
254             # You can likely skip the rest of this synopsis.
255              
256             # object-oriented interface:
257              
258             $tai = Time::TAI::Simple->new();
259              
260             $since_epoch_minus_ten = $tai->time();
261              
262             # download a more up-to-date leapsecond list, and recalculate time base:
263              
264             $tai->download_leapseconds() or die("cannot download leapseconds file");
265             $tai->load_leapseconds();
266             $tai->calculate_base();
267             $since_epoch_minus_ten = $tai->time();
268              
269             # .. or simply download the leapsecond list as part of instantiation.
270             # There is also an option for specifying where to put/find the list:
271              
272             $tai = Time::TAI::Simple->new(
273             download_leapseconds => 1,
274             leapseconds_pathname => '/etc/leap-seconds.list'
275             );
276             $since_epoch_minus_ten = $tai->time();
277              
278             # use mode parameter for TAI-00 time or TAI-35 time:
279              
280             $tai00 = Time::TAI::Simple->new(mode => 'tai');
281             $seconds_since_epoch = $tai00->time();
282              
283             $tai35 = Time::TAI::Simple->new(mode => 'tai35');
284             $close_to_utc_time_for_now = $tai35->time();
285              
286             # reduce processing overhead of instantiation, at the expense of
287             # some precision, by turning off fine-tuning step:
288              
289             $tai = Time::TAI::Simple->new(fine_tune => 0);
290             $nowish = $tai->time(); # accurate to a few milliseconds, not microseconds.
291              
292             =head1 DESCRIPTION
293              
294             The C module provides a very simple way to obtain the
295             number of seconds elapsed since the beginning of the UNIX epoch (January
296             1st, 1970).
297              
298             It differs from C in that it returns the actual number of
299             elapsed seconds, unmodified by the leap seconds introduced by the IETF
300             to make UTC time. These leap seconds can be problematic for automation
301             software, as they effectively make the system clock stand still for one
302             second every few years.
303              
304             D. J. Bernstein describes other problems with leapseconds-adjusted time
305             in this short and sweet article: L
306              
307             C provides a monotonically increasing count of seconds,
308             which means it will never stand still or leap forward or backward due to
309             system clock adjustments (such as from NTP), and avoids leapseconds-related
310             problems in general.
311              
312             This module differs from L
313             and L in a few
314             ways:
315              
316             =over 4
317              
318             * it is much simpler to use,
319              
320             * it uses the same epoch as perl's C
321              
322             * it is a "best effort" implementation, accurate to a few microseconds,
323              
324             * it depends on the local POSIX monotonic clock, not an external atomic clock.
325              
326             =back
327              
328             =head1 ABOUT TAI, TAI10, TAI35
329              
330             This module provides three I of TAI time:
331              
332             B is, very simply, the actual number of elapsed seconds since the epoch.
333              
334             B provides TAI-10 seconds, which is how TAI time has traditionally been
335             most commonly used, because when leapseconds were introduced in 1972, UTC was
336             TAI minus 10 seconds.
337              
338             It is the type of time provided by Arthur David Olson's popular time library,
339             and by the TAI patch currently proposed to the standard zoneinfo implementation.
340             When most people use TAI time, it is usually TAI-10.
341              
342             B provides TAI-35 seconds, which makes it exactly equal to the system
343             clock time returned by C before July 1 2015.
344             As the IETF introduces more leapseconds, B will be one second ahead
345             of the system clock time with each introduction.
346              
347             This mode is provided for use-cases where compatability with other TAI time
348             implementations is not required, and keeping the monotonically increasing time
349             relatively close to the system clock time is desirable.
350              
351             It was decided to provide three types of TAI time instead of allowing an
352             arbitrary seconds offset parameter to make it easier for different systems
353             with different users and different initialization times to pick compatible
354             time modes.
355              
356             =head1 FURTHER READING
357              
358             The following reading is recommended:
359              
360             L
361              
362             L
363              
364             L
365              
366             =head1 MODULE-SCOPE VARIABLES
367              
368             C defines a few externally-accessible variables so that
369             users may customize their values to fit their needs, or to use them in
370             other programming projects.
371              
372             =head2 C<@Time::TAI::Simple::LEAPSECOND_UNIX_PATHNAME_LIST>
373              
374             This list enumerates the pathnames where methods will look for the file
375             listing IETF-defined leapseconds on UNIX systems. The list is traversed
376             in order, and the first readable file will be used.
377              
378             =head2 C<@Time::TAI::Simple::LEAPSECOND_WINDOWS_PATHNAME_LIST>
379              
380             This list enumerates the pathnames where methods will look for the file
381             listing IETF-defined leapseconds on Windows systems. Like its UNIX
382             counterpart, the list is traversed in order, and the first readable file
383             will be used.
384              
385             =head2 C<@Time::TAI::Simple::FALLBACK_LEAPSECONDS_LIST>
386              
387             If no leapseconds list file can be found, C falls back on
388             using this hard-coded list of IETF-defined leapseconds.
389              
390             This is dangerous because if the module is too old to include recently
391             introduced leapseconds, TAI clock objects instantiated after the new
392             leapsecond will be one second ahead of the desired TAI time.
393              
394             This problem can be avoided by downloading the most recent leapsecond list
395             file, either by invoking the C method or by manually
396             downloading it from L
397             and putting it somewhere C will find it, such as
398             C or C.
399              
400             C<@Time::TAI::Simple::FALLBACK_LEAPSECONDS_LIST> is a list of arrayrefs,
401             each referenced array consisting of two elements, an IETF timestamp and a
402             time delta.
403              
404             =head2 C<$Time::TAI::Simple::LEAPSECOND_IETF_DELTA>
405              
406             The IETF represents TAI time as the number of seconds elapsed since 1900-01-01,
407             which is 2208960000 seconds greater than the number of seconds elapsed since
408             1971-01-01 (the UNIX epoch). C keeps this value in
409             C<$Time::TAI::Simple::LEAPSECOND_IETF_DELTA> and uses it internally to convert
410             IETF times to UNIX epoch times.
411              
412             =head2 C<$Time::TAI::Simple::TAI_OR>
413              
414             =head2 C<$Time::TAI::Simple::TAI10_OR>
415              
416             =head2 C<$Time::TAI::Simple::TAI35_OR>
417              
418             When using C's procedural interface, the first time
419             the C, C, and C functions are invoked, they instantiate
420             C with the appropriate C and assign it to these
421             module-scope variables. Subsequent invocations re-use these instants.
422              
423             Before the first invocation, these variables are C.
424              
425             =head1 PROCEDURAL INTERFACE
426              
427             =head2 C<$seconds = tai()>
428              
429             =head2 C<$seconds = tai10()>
430              
431             =head2 C<$seconds = tai35()>
432              
433             These functions return a floating-point number of seconds elapsed since the
434             epoch. They are equivalent to instantiating a C<$tai> object with the
435             corresponding mode and invoking its C
436              
437             B:
438              
439             use Time::TAI::Simple;
440              
441             my $start_time = tai();
442             do_something();
443             my $time_delta = tai() - $start_time;
444             print "doing something took $time_delta seconds\n";
445              
446             =head1 OBJECT ORIENTED INTERFACE
447              
448             =head2 INSTANTIATION
449              
450             =head3 C<$tai = Time::TAI::Simple-Enew(%options)>
451              
452             Instantiates and returns a new C object, hereafter referred
453             to as C<$tai>. Returns C on irrecoverable error.
454              
455             Without options, instantiation will:
456              
457             =over 4
458              
459             * find and load the local copy of the leapseconds file into C<$tai-E{ls_ar}>
460             (or load from C<@Time::TAI::Simple::FALLBACK_LEAPSECONDS_LIST> if no local file
461             is found),
462              
463             * instantiate a C object referencing the POSIX monotonic clock
464             and store it in C<$tai-E{tm_or}>,
465              
466             * calculate a value for C<$tai-E{tm_base}>, which is the number of seconds to
467             add to the POSIX monotonic clock time to derive the TAI-10 time, and
468              
469             * perform a "fine tuning" of this C, based on repeatedly sampling the
470             system clock and estimating the time difference between loading the value of the
471             system clock and loading the value of the monotonic clock.
472              
473             =back
474              
475             This behavior can be changed by passing optional parameters:
476              
477             =over 4
478              
479             =item C 'tai'>
480              
481             =item C 'tai10'> (default)
482              
483             =item C 'tai35'>
484              
485             Adjusts C<$tai-E{tm_base}> so that C<$tai-Etime()> returns the B,
486             B, or B time.
487              
488             =item C 0> (default)
489              
490             =item C 1>
491              
492             When set, causes C to try to http-download a new leapseconds list file
493             before loading the leapseconds file.
494              
495             C maintains an internal list of URLs from which to download
496             this file, and it goes down this list sequentially, stopping when the file has
497             been successfully downloaded. This list may be amended via the C
498             option.
499              
500             By default, no attempt is made to download a leapseconds file. This avoids
501             the potential for very long http timeouts and clobbering any existing
502             administrator-provided leapseconds file.
503              
504             =item C [$url1, $url2, ...]>
505              
506             Prepends the provided list of URLs to the list of remove locations from which
507             the leapseconds file is downloaded when the C option is
508             set. Use this if your administrator maintains a leapseconds file for
509             organizational use.
510              
511             =item C '/home/tai/leap-seconds.list'>
512              
513             Sets the pathname of the leapseconds list file. This is the pathname to which
514             the file will be stored when downloaded via the C option
515             or C method, and it is the pathname from which the file
516             will be loaded by the C method.
517              
518             By default, C will look for this file in several locations,
519             specified in C<@Time::TAI::Simple::LEAPSECOND_UNIX_PATHNAME_LIST> and
520             C<@Time::TAI::Simple::LEAPSECOND_WINDOWS_PATHNAME_LIST>. The user may opt
521             to replace the contents of these list variables as an alternative to using
522             the C option (for instance, before invoking the C,
523             C, C functions).
524              
525             =item C 0> (default)
526              
527             =item C 1>
528              
529             When set, prevents loading the timestamp list from the timestamp list file
530             or C<@Time::TAI::Simple::FALLBACK_LEAPSECONDS_LIST> into C<$tai-E{ls_ar}>.
531              
532             This only makes sense when setting the C option or when populating
533             C<$tai-E{ls_ar}> manually after instantiation and subsequently re-running the
534             C method.
535              
536             =item C $seconds>
537              
538             When set, circumvents the normal process of calculating C<$tai-E{tm_base}>
539             and uses the provided value instead. This should be the number of seconds
540             added to the time obtained from the POSIX monotonic clock to get the TAI
541             time returned by the C
542              
543             =item C 0>
544              
545             =item C 1> (default)
546              
547             When set (the default), adjusts C, based on repeatedly sampling the
548             system clock and estimating the time difference between loading the value of the
549             system clock and loading the value of the monotonic clock. This can add measurable
550             overhead to the C method -- about 35 microseconds on 2013-era
551             hardware, accounting for about 3/4 of instantiation time.
552              
553             When false, skips this fine-tuning, diminishing the precision of the C
554             method from a few microseconds to a few milliseconds.
555              
556             =back
557              
558             =head2 OBJECT ATTRIBUTES
559              
560             The following attributes of a C instance are public. Changes to
561             some attributes will do nothing until the C and/or C
562             methods are re-run.
563              
564             =head3 C (hash reference)
565              
566             Refers to the parameters passed to C.
567              
568             =head3 C (C object reference)
569              
570             Refers to the POSIX standard monotonic clock interface used by C
571             the current TAI time (along with C).
572              
573             =head3 C (array reference)
574              
575             Refers to the IETF leapseconds list. Its elements are arrayrefs to
576             C<[UTC epoch, seconds]> tuples, and they are ordered by C.
577              
578             =head3 C (integer)
579              
580             Value is the file modification time of the IETF leapseconds list file, if C
581             was loaded from a file, or the time C was loaded from
582             C<@Time::TAI::Simple::FALLBACK_LEAPSECONDS_LIST>, or C<0> if never loaded.
583              
584             =head3 C (floating point)
585              
586             Value is the system clock time the C method last attempted to
587             download the IETF leapseconds list file, or C<0.0> if never attempted.
588              
589             =head3 C (floating point)
590              
591             Value is the difference, in seconds, between the POSIX monotonic clock time
592             and the beginning of the epoch. It is used by C
593             TAI time. It is initialized by the C method, and is C<0.0> if
594             never initialized.
595              
596             =head3 C (string)
597              
598             Exactly one of "tai", "tai10", "tai35", indicating the C with which the
599             object was instantiated, and thus the type of TAI time returned by C
600             Its default value is "tai10".
601              
602             =head2 OBJECT METHODS
603              
604             =head3 C<$tai-Etime()>
605              
606             Returns a floating-point number of seconds elapsed since the epoch.
607              
608             =head3 C<$tai-Ecalculate_base(%options)>
609              
610             C uses the POSIX monotonic clock, the leapsecond list, and
611             the system clock to calculate C<$tai-E{tm_base}>, which is the difference
612             between the POSIX monotonic clock and the TAI time. This difference is used
613             by C
614              
615             This method is normally only called by C, but can be called explicitly
616             to recalculate C<$tai-E{tm_base}> if one of its dependencies is changed.
617              
618             It takes some of the same options as C, and they have the same effect:
619              
620             =over 4
621              
622             =item C $seconds>
623              
624             =item C 0 or 1>
625              
626             =back
627              
628             It has no return value.
629              
630             =head3 C<$tai-Eload_leapseconds(%options)>
631              
632             C finds the local copy of the IETF leapseconds list file,
633             reads it, and populates the object's C attribute. If it cannot find
634             any file it uses the values in C<@Time::TAI::Simple::FALLBACK_LEAPSECONDS_LIST>
635             instead.
636              
637             This method, too, is normally only called by C, but can be called
638             explicitly as needed to re-initialize C<$tai-E{ls_ar}>.
639              
640             For now it takes only one option, which has the same effect as passing it
641             to :
642              
643             =over 4
644              
645             =item C "/home/tai/leap-seconds.list">
646              
647             =back
648              
649             It returns 1 on success, 0 on failure.
650              
651             =head3 C<$tai-Edownload_leapseconds(%options)>
652              
653             C tries to download the IETF leapseconds file so it
654             can be loaded by the C method. It iterates through a
655             list of URLs (any provided via the C parameter first,
656             and an internal list after) and saves the first file it is able to download
657             to either the pathname specified by the C parameter
658             or a sensible location appropriate to the operating system type.
659              
660             This method can be called by C, but only when the C
661             parameter is passed to C with a value which resolves to C.
662              
663             It takes two options, which have the same effects as passing them to C:
664              
665             =over 4
666              
667             =item C [$url1, $url2, ...]>
668              
669             =item C "/home/tai/leap-seconds.list">
670              
671             =back
672              
673             It returns 1 on success, 0 on failure.
674              
675             =head1 EXAMPLES
676              
677             Some simple scripts wrapping this module can be found in C:
678              
679             =over 4
680              
681             =item C
682              
683             Attempts to download the IETF leapseconds file. Will write the pathname of
684             the downloaded file to STDOUT and exit C<0>, or write an error to STDERR and
685             exit C<1>. Pass it the C<-h> option to see its options.
686              
687             On UNIX hosts, it is recommended that a symlink be made in C
688             to C so that it updates the system's
689             leapseconds file as updates become available.
690              
691             =item C
692              
693             Prints the current time. Shows TAI-10 by default. Pass it the C<-h> option
694             to see its options.
695              
696             =back
697              
698             =head1 TODO
699              
700             Needs more unit tests.
701              
702             Does C need changes to be made thread-safe?
703              
704             Test C<_fine_tune> under other versions of perl, find out if the constant factor needs
705             to be version-specific.
706              
707             Do something smart with C and C, like an optional feature which tries to
708             refresh the leapsecond list periodically when stale.
709              
710             =head1 THREADS
711              
712             Not tested, but its dependencies are purportedly thread-safe, and I think the C
713             method, and the C, C, and C functions should be thread-safe. Not
714             so sure about C.
715              
716             =head1 BUGS
717              
718             Probably. In particular, the Windows compatability code is not tested, nor do I have
719             access to a Windows environment in which to test it. I doubt that the paths in
720             C<@Time::TAI::Simple::LEAPSECOND_WINDOWS_PATHNAME_LIST> are sufficient for all
721             environments.
722              
723             Also, some corners were cut in C, particularly in the C<--iso> code,
724             which means its output will not be precisely correct for locales with timezones
725             whose time offsets are not whole hours.
726              
727             Please report relevant bugs to .
728              
729             Bugfix patches are also welcome.
730              
731             =head1 SEE ALSO
732              
733             L has a C method which will give the actual
734             difference between two times, just like taking the difference between two TAI times.
735              
736             If you are a scientist, you might want
737             L or
738             L.
739              
740             An alternative approach to solving the problem of leapsecond-induced bugs
741             is L, "UTC with Smoothed
742             Leap Seconds".
743              
744             =head1 AUTHOR
745              
746             TTK Ciar,
747              
748             =head1 COPYRIGHT AND LICENSE
749              
750             Copyright 2014-2017 by TTK Ciar
751              
752             This library is free software; you can redistribute it and/or modify it under
753             the same terms as Perl itself.
754              
755             =cut