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