| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
=head1 NAME |
|
2
|
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
Time::UTC_SLS - UTC with Smoothed Leap Seconds |
|
4
|
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
6
|
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
use Time::UTC_SLS qw(utc_to_utcsls utcsls_to_utc); |
|
8
|
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
$mjd = utc_to_utcsls($day, $secs); |
|
10
|
|
|
|
|
|
|
($day, $secs) = utcsls_to_day($mjd); |
|
11
|
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
use Time::UTC_SLS qw( |
|
13
|
|
|
|
|
|
|
utc_day_to_mjdn utc_mjdn_to_day |
|
14
|
|
|
|
|
|
|
utc_day_to_cjdn utc_cjdn_to_day); |
|
15
|
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
$mjdn = utc_day_to_mjdn($day); |
|
17
|
|
|
|
|
|
|
$day = utc_mjdn_to_day($mjdn); |
|
18
|
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
$cjdn = utc_day_to_cjdn($day); |
|
20
|
|
|
|
|
|
|
$day = utc_cjdn_to_day($cjdn); |
|
21
|
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
23
|
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
Coordinated Universal Time (UTC) is a time scale with days of unequal |
|
25
|
|
|
|
|
|
|
lengths, due to leap seconds, in order to keep in step with both Terran |
|
26
|
|
|
|
|
|
|
rotation (Universal Time, UT) and International Atomic Time (TAI). |
|
27
|
|
|
|
|
|
|
Some applications that wish to use a time scale that maintains both of |
|
28
|
|
|
|
|
|
|
these relations can't cope with unequal day lengths, and so cannot use |
|
29
|
|
|
|
|
|
|
UTC properly. UTC with Smoothed Leap Seconds (UTC-SLS) is another option |
|
30
|
|
|
|
|
|
|
in such cases. UTC-SLS is a time scale that usually matches UTC exactly |
|
31
|
|
|
|
|
|
|
but changes rate in the time leading up to a leap second in order to |
|
32
|
|
|
|
|
|
|
make every day appear to be exactly the same length. |
|
33
|
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
On a normal UTC day, of length 86400 UTC seconds, UTC and UTC-SLS |
|
35
|
|
|
|
|
|
|
behave identically. On a day with a leap second, thus having 86401 or |
|
36
|
|
|
|
|
|
|
(theoretically) 86399 UTC seconds, UTC and UTC-SLS behave identically |
|
37
|
|
|
|
|
|
|
for most of the day, but the last 1000 UTC seconds correspond to 999 or |
|
38
|
|
|
|
|
|
|
(theoretically) 1001 UTC-SLS seconds. Thus every UTC-SLS day has exactly |
|
39
|
|
|
|
|
|
|
86400 UTC-SLS seconds. UTC and UTC-SLS are equal on every half hour, |
|
40
|
|
|
|
|
|
|
and in particular the day boundaries (at midnight) are in the same place |
|
41
|
|
|
|
|
|
|
on both time scales. See L |
|
42
|
|
|
|
|
|
|
for further explanation. |
|
43
|
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
UTC-SLS is defined for the post-1972 form of UTC, using leap seconds. |
|
45
|
|
|
|
|
|
|
The prior form, from 1961, using `rubber seconds' as well as leaps, |
|
46
|
|
|
|
|
|
|
could be treated in a similar manner, but the exact algorithm has not |
|
47
|
|
|
|
|
|
|
been defined. The rubber seconds system was itself trying to achieve |
|
48
|
|
|
|
|
|
|
part of what UTC-SLS does. |
|
49
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
This module represents instants on the UTC scale by the combination of |
|
51
|
|
|
|
|
|
|
a day number and a number of seconds since midnight within the day. |
|
52
|
|
|
|
|
|
|
In this module the day number is the integral number of days since |
|
53
|
|
|
|
|
|
|
1958-01-01, which is the epoch of TAI. This is the convention used by |
|
54
|
|
|
|
|
|
|
the C module. Instants on the UTC-SLS scale are represented |
|
55
|
|
|
|
|
|
|
by a Modified Julian Date, which is a fractional count of days since |
|
56
|
|
|
|
|
|
|
1858-11-17T00Z. The MJD is a suitable interchange format between |
|
57
|
|
|
|
|
|
|
date-manipulation modules. |
|
58
|
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
All numbers in this API are C objects. All numeric function |
|
60
|
|
|
|
|
|
|
arguments must be Cs, and all numeric values returned are |
|
61
|
|
|
|
|
|
|
likewise Cs. |
|
62
|
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
=cut |
|
64
|
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
package Time::UTC_SLS; |
|
66
|
|
|
|
|
|
|
|
|
67
|
3
|
|
|
3
|
|
153275
|
{ use 5.006; } |
|
|
3
|
|
|
|
|
9
|
|
|
68
|
3
|
|
|
3
|
|
13
|
use warnings; |
|
|
3
|
|
|
|
|
5
|
|
|
|
3
|
|
|
|
|
70
|
|
|
69
|
3
|
|
|
3
|
|
12
|
use strict; |
|
|
3
|
|
|
|
|
10
|
|
|
|
3
|
|
|
|
|
69
|
|
|
70
|
|
|
|
|
|
|
|
|
71
|
3
|
|
|
3
|
|
12
|
use Carp qw(croak); |
|
|
3
|
|
|
|
|
6
|
|
|
|
3
|
|
|
|
|
145
|
|
|
72
|
3
|
|
|
3
|
|
1332
|
use Math::BigRat 0.04; |
|
|
3
|
|
|
|
|
207257
|
|
|
|
3
|
|
|
|
|
19
|
|
|
73
|
3
|
|
|
|
|
358
|
use Time::UTC 0.007 qw( |
|
74
|
|
|
|
|
|
|
utc_day_seconds |
|
75
|
|
|
|
|
|
|
utc_day_to_mjdn utc_mjdn_to_day |
|
76
|
|
|
|
|
|
|
utc_day_to_cjdn utc_cjdn_to_day |
|
77
|
3
|
|
|
3
|
|
4322
|
); |
|
|
3
|
|
|
|
|
66210
|
|
|
78
|
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
our $VERSION = "0.005"; |
|
80
|
|
|
|
|
|
|
|
|
81
|
3
|
|
|
3
|
|
80
|
use parent "Exporter"; |
|
|
3
|
|
|
|
|
9
|
|
|
|
3
|
|
|
|
|
19
|
|
|
82
|
|
|
|
|
|
|
our @EXPORT_OK = qw( |
|
83
|
|
|
|
|
|
|
utc_to_utcsls utcsls_to_utc |
|
84
|
|
|
|
|
|
|
utc_day_to_mjdn utc_mjdn_to_day |
|
85
|
|
|
|
|
|
|
utc_day_to_cjdn utc_cjdn_to_day |
|
86
|
|
|
|
|
|
|
); |
|
87
|
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
=head1 FUNCTIONS |
|
89
|
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
=over |
|
91
|
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
=item utc_to_utcsls(DAY, SECS) |
|
93
|
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
Converts from UTC to UTC-SLS. The input is a UTC instant expressed as a |
|
95
|
|
|
|
|
|
|
day number and a number of seconds since midnight, both as C |
|
96
|
|
|
|
|
|
|
objects. Returns the corresponding UTC-SLS instant expressed as a |
|
97
|
|
|
|
|
|
|
Modified Julian Date, as a C object. |
|
98
|
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
=cut |
|
100
|
|
|
|
|
|
|
|
|
101
|
3
|
|
|
3
|
|
246
|
use constant UTCSLS_START_DAY => Math::BigRat->new(5113); |
|
|
3
|
|
|
|
|
6
|
|
|
|
3
|
|
|
|
|
19
|
|
|
102
|
3
|
|
|
3
|
|
1900
|
use constant TAI_EPOCH_MJD => Math::BigRat->new(36204); |
|
|
3
|
|
|
|
|
5
|
|
|
|
3
|
|
|
|
|
11
|
|
|
103
|
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
sub utc_to_utcsls($$) { |
|
105
|
26
|
|
|
26
|
1
|
61755
|
my($day, $secs) = @_; |
|
106
|
26
|
100
|
|
|
|
89
|
croak "day $day precedes the start of UTC-SLS" |
|
107
|
|
|
|
|
|
|
unless $day >= UTCSLS_START_DAY; |
|
108
|
22
|
100
|
100
|
|
|
1510
|
unless($secs >= 0 && $secs <= 85399) { |
|
109
|
13
|
|
|
|
|
14081
|
my $day_len = utc_day_seconds($day); |
|
110
|
13
|
100
|
100
|
|
|
475816
|
croak "$secs seconds is out of range for a $day_len second day" |
|
111
|
|
|
|
|
|
|
if $secs < 0 || $secs >= $day_len; |
|
112
|
9
|
100
|
|
|
|
5904
|
if($day_len != 86400) { |
|
113
|
7
|
50
|
33
|
|
|
4129
|
croak "UTC-SLS is not defined for a $day_len ". |
|
114
|
|
|
|
|
|
|
"second day" |
|
115
|
|
|
|
|
|
|
unless $day_len == 86399 || $day_len == 86401; |
|
116
|
7
|
|
|
|
|
7949
|
my $slew_from = $day_len - 1000; |
|
117
|
7
|
100
|
|
|
|
4995
|
$secs = $slew_from + (86400 - $slew_from) * |
|
118
|
|
|
|
|
|
|
($secs - $slew_from)/1000 |
|
119
|
|
|
|
|
|
|
if $secs > $slew_from; |
|
120
|
|
|
|
|
|
|
} |
|
121
|
|
|
|
|
|
|
} |
|
122
|
18
|
|
|
|
|
22291
|
return utc_day_to_mjdn($day) + $secs/86400; |
|
123
|
|
|
|
|
|
|
} |
|
124
|
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
=item utcsls_to_utc(MJD) |
|
126
|
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
Converts from UTC-SLS to UTC. The input is a UTC-SLS instant expressed |
|
128
|
|
|
|
|
|
|
as a Modified Julian Date, as a C object. Returns a list of |
|
129
|
|
|
|
|
|
|
two values, giving the corresponding UTC instant expressed as a day number |
|
130
|
|
|
|
|
|
|
and a number of seconds since midnight, both as C objects. |
|
131
|
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
=cut |
|
133
|
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
sub utcsls_to_utc($) { |
|
135
|
19
|
|
|
19
|
1
|
31217
|
my($mjd) = @_; |
|
136
|
19
|
|
|
|
|
65
|
my $mjdn = $mjd->copy->bfloor; |
|
137
|
19
|
|
|
|
|
1114
|
my $secs = ($mjd - $mjdn) * 86400; |
|
138
|
19
|
|
|
|
|
18736
|
my $day = $mjdn - TAI_EPOCH_MJD; |
|
139
|
19
|
100
|
|
|
|
3302
|
croak "day $day precedes the start of UTC-SLS" |
|
140
|
|
|
|
|
|
|
unless $day >= UTCSLS_START_DAY; |
|
141
|
18
|
100
|
|
|
|
1122
|
unless($secs <= 85399) { |
|
142
|
9
|
|
|
|
|
5318
|
my $day_len = utc_day_seconds($day); |
|
143
|
9
|
100
|
|
|
|
1521
|
if($day_len != 86400) { |
|
144
|
7
|
50
|
33
|
|
|
4394
|
croak "UTC-SLS is not defined for a $day_len ". |
|
145
|
|
|
|
|
|
|
"second day" |
|
146
|
|
|
|
|
|
|
unless $day_len == 86399 || $day_len == 86401; |
|
147
|
7
|
|
|
|
|
7983
|
my $slew_from = $day_len - 1000; |
|
148
|
7
|
100
|
|
|
|
4884
|
$secs = $slew_from + 1000 * ($secs - $slew_from)/ |
|
149
|
|
|
|
|
|
|
(86400 - $slew_from) |
|
150
|
|
|
|
|
|
|
if $secs > $slew_from; |
|
151
|
|
|
|
|
|
|
} |
|
152
|
|
|
|
|
|
|
} |
|
153
|
18
|
|
|
|
|
16666
|
return ($day, $secs); |
|
154
|
|
|
|
|
|
|
} |
|
155
|
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
=item utc_day_to_mjdn(DAY) |
|
157
|
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
Takes a day number (days since the TAI epoch), as a C |
|
159
|
|
|
|
|
|
|
object, and returns the corresponding Modified Julian Day Number |
|
160
|
|
|
|
|
|
|
(a number of days since 1858-11-17 UT), as a C object. |
|
161
|
|
|
|
|
|
|
MJDN is a standard numbering for days in Universal Time. There is no |
|
162
|
|
|
|
|
|
|
bound on the permissible day numbers; the function is not limited to |
|
163
|
|
|
|
|
|
|
days for which UTC-SLS is defined. |
|
164
|
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
=item utc_mjdn_to_day(MJDN) |
|
166
|
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
This performs the reverse of the translation that C does. |
|
168
|
|
|
|
|
|
|
It takes a Modified Julian Day Number, as a C object, |
|
169
|
|
|
|
|
|
|
and returns the number of days since the TAI epoch, as a C |
|
170
|
|
|
|
|
|
|
object. It does not impose any limit on the range. |
|
171
|
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
=item utc_day_to_cjdn(DAY) |
|
173
|
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
Takes a day number (days since the TAI epoch), as a C |
|
175
|
|
|
|
|
|
|
object, and returns the corresponding Chronological Julian Day Number |
|
176
|
|
|
|
|
|
|
(a number of days since -4713-11-24), as a C object. |
|
177
|
|
|
|
|
|
|
CJDN is a standard day numbering that is useful as an interchange format |
|
178
|
|
|
|
|
|
|
between implementations of different calendars. There is no bound on |
|
179
|
|
|
|
|
|
|
the permissible day numbers; the function is not limited to days for |
|
180
|
|
|
|
|
|
|
which UTC-SLS is defined. |
|
181
|
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
=item utc_cjdn_to_day(CJDN) |
|
183
|
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
This performs the reverse of the translation that C does. |
|
185
|
|
|
|
|
|
|
It takes a Chronological Julian Day Number, as a C object, |
|
186
|
|
|
|
|
|
|
and returns the number of days since the TAI epoch, as a C |
|
187
|
|
|
|
|
|
|
object. It does not impose any limit on the range. |
|
188
|
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
=back |
|
190
|
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
=head1 SEE ALSO |
|
192
|
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
L, |
|
194
|
|
|
|
|
|
|
L, |
|
195
|
|
|
|
|
|
|
L |
|
196
|
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
=head1 AUTHOR |
|
198
|
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
Andrew Main (Zefram) |
|
200
|
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
=head1 COPYRIGHT |
|
202
|
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
Copyright (C) 2006, 2007, 2009, 2010, 2012, 2017 |
|
204
|
|
|
|
|
|
|
Andrew Main (Zefram) |
|
205
|
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
=head1 LICENSE |
|
207
|
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
This module is free software; you can redistribute it and/or modify it |
|
209
|
|
|
|
|
|
|
under the same terms as Perl itself. |
|
210
|
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
=cut |
|
212
|
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
1; |