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
|
|
169426
|
use strict; |
|
2
|
|
|
|
|
10
|
|
|
2
|
|
|
|
|
41
|
|
6
|
2
|
|
|
2
|
|
7
|
use warnings; |
|
2
|
|
|
|
|
2
|
|
|
2
|
|
|
|
|
60
|
|
7
|
|
|
|
|
|
|
require v5.10.0; |
8
|
|
|
|
|
|
|
|
9
|
2
|
|
|
2
|
|
647
|
use POSIX::RT::Clock; |
|
2
|
|
|
|
|
1471
|
|
|
2
|
|
|
|
|
39
|
|
10
|
2
|
|
|
2
|
|
8
|
use Time::HiRes; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
6
|
|
11
|
2
|
|
|
2
|
|
1017
|
use HTTP::Tiny; |
|
2
|
|
|
|
|
68629
|
|
|
2
|
|
|
|
|
62
|
|
12
|
|
|
|
|
|
|
|
13
|
2
|
|
|
2
|
|
13
|
use base qw(Exporter); |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
143
|
|
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
BEGIN { |
16
|
2
|
|
|
2
|
|
6
|
@Time::TAI::Simple::EXPORT = qw(tai tai10 tai35); |
17
|
2
|
|
|
|
|
2297
|
$Time::TAI::Simple::VERSION = '1.14'; |
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 http://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
|
6058
|
my ($class, %opt_hr) = @_; |
72
|
2004
|
|
|
|
|
1667
|
my $success = 0; |
73
|
2004
|
|
|
|
|
1554
|
my $timer = undef; |
74
|
2004
|
|
|
|
|
1653
|
eval { $timer = POSIX::RT::Clock->new('monotonic'); $success = 1; }; |
|
2004
|
|
|
|
|
2838
|
|
|
2004
|
|
|
|
|
1697
|
|
75
|
2004
|
50
|
|
|
|
2207
|
return undef unless ($success); |
76
|
|
|
|
|
|
|
|
77
|
2004
|
|
|
|
|
5372
|
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
|
|
|
|
|
1959
|
bless ($self, $class); |
89
|
2004
|
|
|
|
|
2502
|
$self->{http_or} = HTTP::Tiny->new(max_redirect => 15); |
90
|
2004
|
|
|
|
|
96885
|
$self->{mode} = $self->opt('mode', 'tai10'); |
91
|
2004
|
50
|
|
|
|
2009
|
$self->download_leapseconds() if ($self->opt('download_leapseconds', 0)); |
92
|
2004
|
100
|
|
|
|
2003
|
$self->load_leapseconds() unless ($self->opt('do_not_load_leapseconds')); |
93
|
2004
|
|
|
|
|
2511
|
$self->calculate_base(); # also sets tm_or and potentially ls_next |
94
|
2004
|
|
|
|
|
5949
|
return $self; |
95
|
|
|
|
|
|
|
} |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
sub time { |
98
|
3
|
|
|
3
|
1
|
10
|
return $_[0]->{tm_or}->get_time() + $_[0]->{tm_base}; |
99
|
|
|
|
|
|
|
} |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
sub tai { |
102
|
1
|
50
|
|
1
|
1
|
7
|
$TAI_OR = Time::TAI::Simple->new(mode => 'tai') unless (defined($TAI_OR)); |
103
|
1
|
|
|
|
|
2
|
return $TAI_OR->time(); |
104
|
|
|
|
|
|
|
} |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
sub tai10 { |
107
|
1
|
50
|
|
1
|
1
|
9
|
$TAI10_OR = Time::TAI::Simple->new(mode => 'tai10') unless (defined($TAI10_OR)); |
108
|
1
|
|
|
|
|
3
|
return $TAI10_OR->time(); |
109
|
|
|
|
|
|
|
} |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
sub tai35 { |
112
|
1
|
50
|
|
1
|
1
|
442
|
$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
|
1727
|
my ($self, %opt_h) = @_; |
118
|
2004
|
50
|
|
|
|
4196
|
$self->{tm_or} = POSIX::RT::Clock->new('monotonic') unless (defined($self->{tm_or})); |
119
|
2004
|
50
|
|
|
|
2422
|
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
|
|
|
|
|
2529
|
my $tm = Time::HiRes::time(); |
124
|
2004
|
|
|
|
|
2435
|
my $mo = $self->{tm_or}->get_time(); |
125
|
2004
|
|
|
|
|
1839
|
my $delta = 0; |
126
|
2004
|
|
|
|
|
2644
|
for (my $ix = 0; defined($self->{ls_ar}->[$ix]); $ix++) { |
127
|
112
|
|
|
|
|
67
|
my ($ls_tm, $ls_delta) = @{$self->{ls_ar}->[$ix]}; |
|
112
|
|
|
|
|
104
|
|
128
|
112
|
50
|
|
|
|
116
|
if ($ls_tm > $tm - $delta) { |
129
|
0
|
|
|
|
|
0
|
$self->{ls_next} = $ix; |
130
|
0
|
|
|
|
|
0
|
last; |
131
|
|
|
|
|
|
|
} |
132
|
112
|
|
|
|
|
126
|
$delta = $ls_delta; |
133
|
|
|
|
|
|
|
} |
134
|
2004
|
100
|
|
|
|
2508
|
$delta -= 10 if ($self->{mode} eq 'tai10'); |
135
|
2004
|
100
|
|
|
|
1977
|
$delta -= 35 if ($self->{mode} eq 'tai35'); |
136
|
2004
|
100
|
|
|
|
1880
|
$delta -= $self->_fine_tune() if ($self->opt('fine_tune', 1)); |
137
|
2004
|
|
|
|
|
2373
|
$self->{tm_base} = $tm - $mo - $delta; |
138
|
2004
|
|
|
|
|
1834
|
return; |
139
|
|
|
|
|
|
|
} |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
sub load_leapseconds { |
142
|
4
|
|
|
4
|
1
|
14
|
my ($self, %opt_h) = @_; |
143
|
4
|
|
|
|
|
6
|
my $filename = $self->_leapseconds_filename(\%opt_h); |
144
|
4
|
|
|
|
|
4
|
my $fh = undef; |
145
|
4
|
|
|
|
|
7
|
$self->{ls_ar} = []; |
146
|
4
|
50
|
|
|
|
49
|
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
|
|
|
|
|
10
|
foreach my $tup (@FALLBACK_LEAPSECONDS_LIST) { |
158
|
112
|
|
|
|
|
67
|
my ($iers_tm, $nsec) = @{$tup}; |
|
112
|
|
|
|
|
93
|
|
159
|
112
|
|
|
|
|
86
|
my $epoch_tm = $iers_tm - $LEAPSECOND_IETF_DELTA; |
160
|
112
|
|
|
|
|
72
|
push(@{$self->{ls_ar}}, [$epoch_tm, $nsec]); |
|
112
|
|
|
|
|
155
|
|
161
|
|
|
|
|
|
|
} |
162
|
4
|
|
|
|
|
6
|
$self->{ls_tm} = CORE::time(); |
163
|
|
|
|
|
|
|
} |
164
|
4
|
|
|
|
|
10
|
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, 'http://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
|
9598
|
my ($self, $name, $default_value, $alt_hr) = @_; |
199
|
10024
|
100
|
|
|
|
13211
|
return $self->{opt_hr}->{$name} if (defined($self->{opt_hr}->{$name})); |
200
|
7021
|
50
|
66
|
|
|
10895
|
return $alt_hr->{$name} if (defined($alt_hr) && ref($alt_hr) eq 'HASH' && defined($alt_hr->{$name})); |
|
|
|
66
|
|
|
|
|
201
|
7021
|
|
|
|
|
8543
|
return $default_value; |
202
|
|
|
|
|
|
|
} |
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
sub _fine_tune { |
205
|
1004
|
|
|
1004
|
|
917
|
my $self = shift(@_); |
206
|
1004
|
|
|
|
|
676
|
my $sum = 0; |
207
|
1004
|
|
|
|
|
1093
|
for (my $i = 0; $i < 100; $i++ ) { |
208
|
100400
|
|
|
|
|
131658
|
$sum += 0 - Time::HiRes::time() + Time::HiRes::time(); |
209
|
|
|
|
|
|
|
} |
210
|
1004
|
|
|
|
|
891
|
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
|
|
|
|
|
1148
|
return $jitter; |
213
|
|
|
|
|
|
|
} |
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
sub _leapseconds_filename { |
216
|
4
|
|
|
4
|
|
5
|
my($self, $opt_hr) = @_; |
217
|
4
|
|
50
|
|
|
7
|
$opt_hr //= {}; |
218
|
4
|
|
|
|
|
5
|
my $pathname = $self->opt('leapseconds_pathname', undef, $opt_hr); |
219
|
4
|
50
|
|
|
|
6
|
return $pathname if (defined($pathname)); |
220
|
4
|
50
|
|
|
|
10
|
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
|
|
|
|
|
15
|
$pathname = $f; |
228
|
16
|
50
|
|
|
|
160
|
return $f if (-e $f); |
229
|
|
|
|
|
|
|
} |
230
|
|
|
|
|
|
|
} |
231
|
4
|
|
|
|
|
10
|
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 |