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