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