line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
=head1 NAME |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
Date::Darian::Mars - the Darian calendar for Mars |
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
=head1 SYNOPSIS |
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
use Date::Darian::Mars qw(present_y); |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
print present_y($y); |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
use Date::Darian::Mars qw( |
12
|
|
|
|
|
|
|
month_days cmsdn_to_ymd ymd_to_cmsdn present_ymd); |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
$md = month_days(209, 23); |
15
|
|
|
|
|
|
|
($y, $m, $d) = cmsdn_to_ymd(546236); |
16
|
|
|
|
|
|
|
$cmsdn = ymd_to_cmsdn(209, 23, 18); |
17
|
|
|
|
|
|
|
print present_ymd(546236); |
18
|
|
|
|
|
|
|
print present_ymd(209, 23, 18); |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
use Date::Darian::Mars qw( |
21
|
|
|
|
|
|
|
year_days cmsdn_to_yd yd_to_cmsdn present_yd); |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
$yd = year_days(209); |
24
|
|
|
|
|
|
|
($y, $d) = cmsdn_to_yd(546236); |
25
|
|
|
|
|
|
|
$cmsdn = yd_to_cmsdn(209, 631); |
26
|
|
|
|
|
|
|
print present_yd(546236); |
27
|
|
|
|
|
|
|
print present_yd(209, 631); |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
=head1 DESCRIPTION |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
The Darian calendar for Mars is a mechanism by which Martian solar days |
32
|
|
|
|
|
|
|
(also known as "sols") can be labelled in a manner useful to inhabitants |
33
|
|
|
|
|
|
|
of Mars. This module provides functions to convert dates between the |
34
|
|
|
|
|
|
|
Darian calendar and Chronological Mars Solar Day Numbers, which is a |
35
|
|
|
|
|
|
|
suitable format to do arithmetic with. It also supplies functions that |
36
|
|
|
|
|
|
|
describe the shape of the Darian calendar, to assist in calendrical |
37
|
|
|
|
|
|
|
calculations. It also supplies functions to represent Darian dates |
38
|
|
|
|
|
|
|
textually in a conventional format. |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
The Darian calendar divides time up into years, months, and days. |
41
|
|
|
|
|
|
|
This module also supports dividing the Darian year directly into days, |
42
|
|
|
|
|
|
|
with no months. |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
The Chronological Mars Solar Day Number is an integral number labelling |
45
|
|
|
|
|
|
|
each Martian day, where the day extends from midnight to midnight in |
46
|
|
|
|
|
|
|
whatever time zone is of interest. It is a linear count of days, where |
47
|
|
|
|
|
|
|
each day's number is one greater than the previous day's number. |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
This module places no limit on the range of dates to which it may be |
50
|
|
|
|
|
|
|
applied. All function arguments are permitted to be C or |
51
|
|
|
|
|
|
|
C objects in order to achieve arbitrary range. Native Perl |
52
|
|
|
|
|
|
|
integers are also permitted, as a convenience when the range of dates |
53
|
|
|
|
|
|
|
being handled is known to be sufficiently small. |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
=head1 DARIAN CALENDAR FOR MARS |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
The main cycle in the Darian calendar is the year. It approximates the |
58
|
|
|
|
|
|
|
length of a Martian tropical year (specifically, the northward equinoctal |
59
|
|
|
|
|
|
|
year), and the year starts approximately on the northward equinox. |
60
|
|
|
|
|
|
|
Years are either 668 or 669 Martian solar days long. 669-day years are |
61
|
|
|
|
|
|
|
referred to as "leap years". |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
Each year is divided into 24 months, of nearly equal length. The months |
64
|
|
|
|
|
|
|
are purely nominal: they do not correspond to any astronomical cycle. |
65
|
|
|
|
|
|
|
Each quarter of the year consists of five months of 28 days followed by |
66
|
|
|
|
|
|
|
one month of 27 days, except that the last month of a leap year contains |
67
|
|
|
|
|
|
|
28 days instead of 27. |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
All odd-numbered years are leap years. Even-numbered years are not leap |
70
|
|
|
|
|
|
|
years, except for years divisible by ten which are leap years, except |
71
|
|
|
|
|
|
|
for years divisible by 100 which are not, except for years divisible by |
72
|
|
|
|
|
|
|
500 which are. |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
Days within each month are numbered sequentially, starting at 1. |
75
|
|
|
|
|
|
|
The months have names (in fact several competing sets of names), but this |
76
|
|
|
|
|
|
|
module does not deal with the names. In this module, months within each |
77
|
|
|
|
|
|
|
year are numbered sequentially from 1. |
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
Years are numbered sequentially. Year 0 is the year in which the first |
80
|
|
|
|
|
|
|
known telescopic observations of Mars occurred. Specifically, year 0 |
81
|
|
|
|
|
|
|
started at the midnight that occurred on the Airy meridian (the Martian |
82
|
|
|
|
|
|
|
prime meridian) at approximately MJD -91195.22 in Terrestrial Time. |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
The calendar is described canonically, and in more detail, at |
85
|
|
|
|
|
|
|
L. |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
The day when Mars Exploration Rover "Opportunity" landed in Meridiani |
88
|
|
|
|
|
|
|
Planum was 0209-23-18 or 0209-631 in the Darian calendar, and CMSDN |
89
|
|
|
|
|
|
|
546236. |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
=cut |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
package Date::Darian::Mars; |
94
|
|
|
|
|
|
|
|
95
|
3
|
|
|
3
|
|
221260
|
{ use 5.006; } |
|
3
|
|
|
|
|
15
|
|
96
|
3
|
|
|
3
|
|
26
|
use warnings; |
|
3
|
|
|
|
|
11
|
|
|
3
|
|
|
|
|
121
|
|
97
|
3
|
|
|
3
|
|
22
|
use strict; |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
109
|
|
98
|
|
|
|
|
|
|
|
99
|
3
|
|
|
3
|
|
21
|
use Carp qw(croak); |
|
3
|
|
|
|
|
7
|
|
|
3
|
|
|
|
|
242
|
|
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
our $VERSION = "0.004"; |
102
|
|
|
|
|
|
|
|
103
|
3
|
|
|
3
|
|
1785
|
use parent "Exporter"; |
|
3
|
|
|
|
|
1260
|
|
|
3
|
|
|
|
|
21
|
|
104
|
|
|
|
|
|
|
our @EXPORT_OK = qw( |
105
|
|
|
|
|
|
|
present_y |
106
|
|
|
|
|
|
|
month_days cmsdn_to_ymd ymd_to_cmsdn present_ymd |
107
|
|
|
|
|
|
|
year_days cmsdn_to_yd yd_to_cmsdn present_yd |
108
|
|
|
|
|
|
|
); |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
# _numify(A): turn possibly-object number into native Perl integer |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
sub _numify($) { |
113
|
248
|
|
|
248
|
|
40633
|
my($a) = @_; |
114
|
248
|
100
|
|
|
|
874
|
return ref($a) eq "" ? $a : $a->numify; |
115
|
|
|
|
|
|
|
} |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
# _fdiv(A, B): divide A by B, flooring remainder |
118
|
|
|
|
|
|
|
# |
119
|
|
|
|
|
|
|
# B must be a positive Perl integer. A may be a Perl integer, Math::BigInt, |
120
|
|
|
|
|
|
|
# or Math::BigRat. The result has the same type as A. |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
sub _fdiv($$) { |
123
|
188
|
|
|
188
|
|
364
|
my($a, $b) = @_; |
124
|
188
|
100
|
|
|
|
467
|
if(ref($a) eq "Math::BigRat") { |
125
|
36
|
|
|
|
|
138
|
return ($a / $b)->bfloor; |
126
|
|
|
|
|
|
|
} else { |
127
|
152
|
100
|
|
|
|
314
|
if($a < 0) { |
128
|
3
|
|
|
3
|
|
2665
|
use integer; |
|
3
|
|
|
|
|
53
|
|
|
3
|
|
|
|
|
21
|
|
129
|
8
|
|
|
|
|
547
|
return -(($b - 1 - $a) / $b); |
130
|
|
|
|
|
|
|
} else { |
131
|
3
|
|
|
3
|
|
172
|
use integer; |
|
3
|
|
|
|
|
11
|
|
|
3
|
|
|
|
|
14
|
|
132
|
144
|
|
|
|
|
5746
|
return $a / $b; |
133
|
|
|
|
|
|
|
} |
134
|
|
|
|
|
|
|
} |
135
|
|
|
|
|
|
|
} |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
# _fmod(A, B): A modulo B, flooring remainder |
138
|
|
|
|
|
|
|
# |
139
|
|
|
|
|
|
|
# B must be a positive Perl integer. A may be a Perl integer, Math::BigInt, |
140
|
|
|
|
|
|
|
# or Math::BigRat. The result has the same type as A. |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
sub _fmod($$) { |
143
|
572
|
|
|
572
|
|
123414
|
my($a, $b) = @_; |
144
|
572
|
100
|
|
|
|
1159
|
if(ref($a) eq "Math::BigRat") { |
145
|
74
|
|
|
|
|
264
|
return $a - $b * ($a / $b)->bfloor; |
146
|
|
|
|
|
|
|
} else { |
147
|
498
|
|
|
|
|
1914
|
return $a % $b; |
148
|
|
|
|
|
|
|
} |
149
|
|
|
|
|
|
|
} |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
=head1 FUNCTIONS |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
Numbers in this API may be native Perl integers, C objects, |
154
|
|
|
|
|
|
|
or integer-valued C objects. All three types are acceptable |
155
|
|
|
|
|
|
|
for all parameters, in any combination. In all conversion functions, |
156
|
|
|
|
|
|
|
the most-significant part of the result (which is the only part with |
157
|
|
|
|
|
|
|
unlimited range) is of the same type as the most-significant part of |
158
|
|
|
|
|
|
|
the input. Less-significant parts of results (which have a small range) |
159
|
|
|
|
|
|
|
are consistently native Perl integers. |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
All functions C if given invalid parameters. |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
=head2 Years |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
=over |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
=item present_y(YEAR) |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
Puts the given year number into the conventional textual presentation |
170
|
|
|
|
|
|
|
format. For years [0, 9999] this is simply four digits. For years |
171
|
|
|
|
|
|
|
outside that range it is a sign followed by at least four digits. |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
This is the minimum-length presentation format. If it is desired |
174
|
|
|
|
|
|
|
to use a form that is longer than necessary, such as to use at least |
175
|
|
|
|
|
|
|
five digits for all year numbers, then the right tool is C |
176
|
|
|
|
|
|
|
(see L). |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
=cut |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
sub present_y($) { |
181
|
56
|
|
|
56
|
1
|
126745
|
my($y) = @_; |
182
|
56
|
|
|
|
|
361
|
my($sign, $digits) = ("$y" =~ /\A\+?(-?)0*([0-9]+?)\z/); |
183
|
56
|
100
|
|
|
|
1217
|
$digits = ("0" x (4 - length($digits))).$digits |
184
|
|
|
|
|
|
|
unless length($digits) >= 4; |
185
|
56
|
100
|
100
|
|
|
256
|
$sign = "+" if $sign eq "" && length($digits) > 4; |
186
|
56
|
|
|
|
|
222
|
return $sign.$digits; |
187
|
|
|
|
|
|
|
} |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
=back |
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
=head2 Darian calendar |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
Each year is divided into 24 months, numbered [1, 24]. Each month is |
194
|
|
|
|
|
|
|
divided into days, numbered sequentially from 1. The month lengths |
195
|
|
|
|
|
|
|
are irregular. The year numbers have unlimited range. |
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
=over |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
=item month_days(YEAR, MONTH) |
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
The parameters identify a month, and the function returns the number of |
202
|
|
|
|
|
|
|
days in that month as a native Perl integer. |
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
=cut |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
sub _year_leap($) { |
207
|
210
|
|
|
210
|
|
367
|
my($y) = @_; |
208
|
210
|
|
66
|
|
|
408
|
return _fmod($y, 2) == 1 || |
209
|
|
|
|
|
|
|
(_fmod($y, 10) == 0 && |
210
|
|
|
|
|
|
|
(_fmod($y, 100) != 0 || _fmod($y, 500) == 0)); |
211
|
|
|
|
|
|
|
} |
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
{ |
214
|
|
|
|
|
|
|
sub month_days($$) { |
215
|
142
|
|
|
142
|
1
|
192564
|
my($y, $m) = @_; |
216
|
142
|
50
|
33
|
|
|
663
|
croak "month number $m is out of the range [1, 24]" |
217
|
|
|
|
|
|
|
unless $m >= 1 && $m <= 24; |
218
|
142
|
100
|
|
|
|
355
|
if($m == 24) { |
219
|
53
|
100
|
|
|
|
105
|
return _year_leap($y) ? 28 : 27; |
220
|
|
|
|
|
|
|
} else { |
221
|
89
|
100
|
|
|
|
203
|
return _fmod($m, 6) == 0 ? 27 : 28; |
222
|
|
|
|
|
|
|
} |
223
|
|
|
|
|
|
|
} |
224
|
|
|
|
|
|
|
} |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
=item cmsdn_to_ymd(CMSDN) |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
This function takes a Chronological Mars Solar Day Number and returns |
229
|
|
|
|
|
|
|
a list of a year, month, and day. |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
=cut |
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
sub cmsdn_to_yd($); |
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
sub cmsdn_to_ymd($) { |
236
|
29
|
|
|
29
|
1
|
34814
|
my($cmsdn) = @_; |
237
|
29
|
|
|
|
|
76
|
my($y, $d) = cmsdn_to_yd($cmsdn); |
238
|
29
|
100
|
|
|
|
15090
|
return ($y, 24, 28) if $d == 669; |
239
|
23
|
|
|
|
|
40
|
$d--; |
240
|
23
|
|
|
|
|
55
|
my $sixm = _fdiv($d, 28*6 - 1); |
241
|
23
|
|
|
|
|
48
|
$d -= $sixm * (28*6 - 1); |
242
|
23
|
|
|
|
|
49
|
my $m = _fdiv($d, 28); |
243
|
23
|
|
|
|
|
50
|
return ($y, 1 + 6*$sixm + $m, 1 + _fmod($d, 28)); |
244
|
|
|
|
|
|
|
} |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
=item ymd_to_cmsdn(YEAR, MONTH, DAY) |
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
This performs the reverse of the translation that C does. |
249
|
|
|
|
|
|
|
It takes year, month, and day numbers, and returns the corresponding |
250
|
|
|
|
|
|
|
CMSDN. |
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
=cut |
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
sub yd_to_cmsdn($$); |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
sub ymd_to_cmsdn($$$) { |
257
|
33
|
|
|
33
|
1
|
29959
|
my($y, $m, $d) = @_; |
258
|
33
|
100
|
100
|
|
|
555
|
croak "month number $m is out of the range [1, 24]" |
259
|
|
|
|
|
|
|
unless $m >= 1 && $m <= 24; |
260
|
31
|
|
|
|
|
77
|
$m = _numify($m); |
261
|
31
|
|
|
|
|
85
|
my $md = month_days($y, $m); |
262
|
31
|
100
|
100
|
|
|
7947
|
croak "day number $d is out of the range [1, $md]" |
263
|
|
|
|
|
|
|
unless $d >= 1 && $d <= $md; |
264
|
27
|
|
|
|
|
86
|
return yd_to_cmsdn($y, ($m - 1) * 28 - _fdiv($m - 1, 6) + _numify($d)); |
265
|
|
|
|
|
|
|
} |
266
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
=item present_ymd(CMSDN) |
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
=item present_ymd(YEAR, MONTH, DAY) |
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
Puts the given date into conventional Darian textual presentation format. |
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
If the date is given as a (YEAR, MONTH, DAY) triplet then these are not |
274
|
|
|
|
|
|
|
checked for consistency. The MONTH and DAY values are only checked to |
275
|
|
|
|
|
|
|
ensure that they fit into the fixed number of digits. This allows the |
276
|
|
|
|
|
|
|
use of this function on data other than actual Darian dates. |
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
=cut |
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
sub present_ymd($;$$) { |
281
|
11
|
|
|
11
|
1
|
2974
|
my($y, $m, $d); |
282
|
11
|
100
|
|
|
|
26
|
if(@_ == 1) { |
283
|
2
|
|
|
|
|
6
|
($y, $m, $d) = cmsdn_to_ymd($_[0]); |
284
|
|
|
|
|
|
|
} else { |
285
|
9
|
|
|
|
|
17
|
($y, $m, $d) = @_; |
286
|
9
|
100
|
100
|
|
|
258
|
croak "month number $m is out of the displayable range" |
287
|
|
|
|
|
|
|
unless $m >= 0 && $m < 100; |
288
|
7
|
100
|
100
|
|
|
176
|
croak "day number $d is out of the displayable range" |
289
|
|
|
|
|
|
|
unless $d >= 0 && $d < 100; |
290
|
|
|
|
|
|
|
} |
291
|
7
|
|
|
|
|
14
|
return sprintf("%s-%02d-%02d", present_y($y), |
292
|
|
|
|
|
|
|
_numify($m), _numify($d)); |
293
|
|
|
|
|
|
|
} |
294
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
=back |
296
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
=head2 Ordinal dates |
298
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
Each year is divided into days, numbered sequentially from 1. The year |
300
|
|
|
|
|
|
|
lengths are irregular. The years correspond exactly to those of the |
301
|
|
|
|
|
|
|
Darian calendar. |
302
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
=over |
304
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
=item year_days(YEAR) |
306
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
The parameter identifies a year, and the function returns the number of |
308
|
|
|
|
|
|
|
days in that year as a native Perl integer. |
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
=cut |
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
sub year_days($) { |
313
|
157
|
|
|
157
|
1
|
149599
|
my($y) = @_; |
314
|
157
|
100
|
|
|
|
339
|
return _year_leap($y) ? 669 : 668; |
315
|
|
|
|
|
|
|
} |
316
|
|
|
|
|
|
|
|
317
|
3
|
|
|
3
|
|
3285
|
use constant DARIAN_ZERO_CMSDN => 405871; # 0000-001 |
|
3
|
|
|
|
|
11
|
|
|
3
|
|
|
|
|
390
|
|
318
|
|
|
|
|
|
|
|
319
|
|
|
|
|
|
|
=item cmsdn_to_yd(CMSDN) |
320
|
|
|
|
|
|
|
|
321
|
|
|
|
|
|
|
This function takes a Chronological Mars Solar Day Number and returns |
322
|
|
|
|
|
|
|
a list of a year and ordinal day. |
323
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
=cut |
325
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
sub cmsdn_to_yd($) { |
327
|
58
|
|
|
58
|
1
|
44084
|
my($cmsdn) = @_; |
328
|
3
|
|
|
3
|
|
27
|
use integer; |
|
3
|
|
|
|
|
11
|
|
|
3
|
|
|
|
|
24
|
|
329
|
58
|
|
|
|
|
243
|
my $d = $cmsdn - DARIAN_ZERO_CMSDN; |
330
|
58
|
|
|
|
|
20578
|
my $qcents = _fdiv($d, 668*500 + 296); |
331
|
58
|
|
|
|
|
24610
|
$d = _numify($d - $qcents * (668*500 + 296)); |
332
|
58
|
|
|
|
|
1004
|
my $y = $d / 669; |
333
|
58
|
100
|
|
|
|
201
|
my $leaps = ($y / 2) + ($y+9) / 10 - ($y+99) / 100 + ($y == 0 ? 0 : 1); |
334
|
58
|
|
|
|
|
122
|
$d -= 668 * $y + $leaps; |
335
|
58
|
|
|
|
|
143
|
my $yd = year_days($y); |
336
|
58
|
100
|
|
|
|
161
|
if($d >= $yd) { |
337
|
20
|
|
|
|
|
39
|
$d -= $yd; |
338
|
20
|
|
|
|
|
40
|
$y++; |
339
|
|
|
|
|
|
|
} |
340
|
58
|
|
|
|
|
173
|
return ($qcents*500 + $y, 1 + $d); |
341
|
|
|
|
|
|
|
} |
342
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
=item yd_to_cmsdn(YEAR, DAY) |
344
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
This performs the reverse of the translation that C does. |
346
|
|
|
|
|
|
|
It takes year and ordinal day numbers, and returns the corresponding |
347
|
|
|
|
|
|
|
CMSDN. |
348
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
=cut |
350
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
sub yd_to_cmsdn($$) { |
352
|
57
|
|
|
57
|
1
|
54103
|
my($y, $d) = @_; |
353
|
3
|
|
|
3
|
|
725
|
use integer; |
|
3
|
|
|
|
|
11
|
|
|
3
|
|
|
|
|
15
|
|
354
|
57
|
|
|
|
|
150
|
my $qcents = _fdiv($y, 500); |
355
|
57
|
|
|
|
|
22027
|
$y = _numify($y - $qcents * 500); |
356
|
57
|
|
|
|
|
932
|
my $yd = year_days($y); |
357
|
57
|
100
|
100
|
|
|
587
|
croak "day number $d is out of the range [1, $yd]" |
358
|
|
|
|
|
|
|
unless $d >= 1 && $d <= $yd; |
359
|
54
|
|
|
|
|
115
|
$d = _numify($d); |
360
|
54
|
100
|
|
|
|
203
|
my $leaps = ($y / 2) + ($y+9) / 10 - ($y+99) / 100 + ($y == 0 ? 0 : 1); |
361
|
54
|
|
|
|
|
204
|
return (DARIAN_ZERO_CMSDN + 668*$y + $leaps + ($d - 1)) + |
362
|
|
|
|
|
|
|
$qcents * (668*500 + 296); |
363
|
|
|
|
|
|
|
} |
364
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
=item present_yd(CMSDN) |
366
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
=item present_yd(YEAR, DAY) |
368
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
Puts the given date into the conventional ordinal textual presentation |
370
|
|
|
|
|
|
|
format. |
371
|
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
If the date is given as a (YEAR, DAY) pair then these are not checked |
373
|
|
|
|
|
|
|
for consistency. The DAY value is only checked to ensure that it fits |
374
|
|
|
|
|
|
|
into the fixed number of digits. This allows the use of this function |
375
|
|
|
|
|
|
|
on data other than actual ordinal dates. |
376
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
=cut |
378
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
sub present_yd($;$) { |
380
|
9
|
|
|
9
|
1
|
4180
|
my($y, $d); |
381
|
9
|
100
|
|
|
|
35
|
if(@_ == 1) { |
382
|
2
|
|
|
|
|
10
|
($y, $d) = cmsdn_to_yd($_[0]); |
383
|
|
|
|
|
|
|
} else { |
384
|
7
|
|
|
|
|
24
|
($y, $d) = @_; |
385
|
7
|
100
|
100
|
|
|
377
|
croak "day number $d is out of the displayable range" |
386
|
|
|
|
|
|
|
unless $d >= 0 && $d < 1000; |
387
|
|
|
|
|
|
|
} |
388
|
7
|
|
|
|
|
24
|
return sprintf("%s-%03d", present_y($y), _numify($d)); |
389
|
|
|
|
|
|
|
} |
390
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
=back |
392
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
=head1 SEE ALSO |
394
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
L, |
396
|
|
|
|
|
|
|
L, |
397
|
|
|
|
|
|
|
L |
398
|
|
|
|
|
|
|
|
399
|
|
|
|
|
|
|
=head1 AUTHOR |
400
|
|
|
|
|
|
|
|
401
|
|
|
|
|
|
|
Andrew Main (Zefram) |
402
|
|
|
|
|
|
|
|
403
|
|
|
|
|
|
|
=head1 COPYRIGHT |
404
|
|
|
|
|
|
|
|
405
|
|
|
|
|
|
|
Copyright (C) 2007, 2009, 2011, 2017 |
406
|
|
|
|
|
|
|
Andrew Main (Zefram) |
407
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
=head1 LICENSE |
409
|
|
|
|
|
|
|
|
410
|
|
|
|
|
|
|
This module is free software; you can redistribute it and/or modify it |
411
|
|
|
|
|
|
|
under the same terms as Perl itself. |
412
|
|
|
|
|
|
|
|
413
|
|
|
|
|
|
|
=cut |
414
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
1; |