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