File Coverage

lib/Time/TAI/Simple.pm
Criterion Covered Total %
statement 94 127 74.0
branch 24 48 50.0
condition 5 11 45.4
subroutine 18 19 94.7
pod 8 9 88.8
total 149 214 69.6


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