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 |