| 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 |