File Coverage

lib/Time/TAI/Simple.pm
Criterion Covered Total %
statement 92 127 72.4
branch 23 48 47.9
condition 5 11 45.4
subroutine 18 19 94.7
pod 8 9 88.8
total 146 214 68.2


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