File Coverage

lib/Astro/Montenbruck/Time.pm
Criterion Covered Total %
statement 62 63 98.4
branch 12 12 100.0
condition 4 5 80.0
subroutine 19 20 95.0
pod 13 13 100.0
total 110 113 97.3


line stmt bran cond sub pod time code
1             package Astro::Montenbruck::Time;
2              
3 7     7   340794 use warnings;
  7         23  
  7         248  
4 7     7   39 use strict;
  7         15  
  7         290  
5              
6             our $VERSION = 0.01;
7              
8 7     7   43 use Exporter qw/import/;
  7         15  
  7         1155  
9              
10             our $SEC_PER_DAY = 86400; # Seconds per day
11             our $SEC_PER_CEN = 3155760000;
12             our $J2000 = 2451545; # Standard Julian Date for 1.1.2000 12:00
13             our $J1900 = 2415020; # Standard Julian Date for 31.12.1899 12:00 (astronomical epoch 1900.0)
14             our $SOLAR_TO_SIDEREAL = 1.002737909350795; # Difference in between Sidereal and Solar hour (the former is shorter)
15             our $GREGORIAN_START = 15821004; # Start of Gregorian calendar (YYYYMMDD)
16             our $JD_UNIX_EPOCH = _gmtime2jd(gmtime(0)); # Standard Julian date for the beginning of Unix epoch, Jan 1 1970 on most Unix systems
17              
18             our %EXPORT_TAGS = (
19             all => [
20             qw/jd_cent after_gregorian cal2jd jd2cal jd0 unix2jd jd2mjd mjd2jd
21             jd2unix jdnow t1900 jd2gst jd2lst
22             $SEC_PER_DAY $SEC_PER_CEN $J2000 $J1900 $GREGORIAN_START $JD_UNIX_EPOCH/
23             ],
24             );
25              
26             our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
27              
28 7     7   51 use POSIX;
  7         14  
  7         56  
29 7     7   17783 use Astro::Montenbruck::MathUtils qw/polynome ddd frac to_range/;
  7         20  
  7         6273  
30              
31             sub after_gregorian {
32 82     82 1 2586 my $y = shift;
33 82         140 my $m = shift;
34 82         135 my $d = shift;
35 82         231 my %arg = (gregorian_start => $GREGORIAN_START, @_);
36 82 100       248 return 0 unless defined $arg{gregorian_start};
37 81         299 polynome( 100, $d, $m, $y ) >= $arg{gregorian_start};
38             }
39              
40             sub cal2jd {
41 79     79 1 14322 my $ye = shift;
42 79         140 my $mo = shift;
43 79         159 my $da = shift;
44 79         273 my %arg = (gregorian_start => $GREGORIAN_START, @_);
45              
46 79         193 my $j = $da + 1720996.5;
47 79 100       298 my ( $m, $y ) = ( $mo > 2 ) ? ( $mo, $ye ) : ( $mo + 12, $ye - 1 );
48 79 100       301 if ( after_gregorian( $ye, $mo, $da, %arg ) ) {
49 75         309 $j += int( $y / 400 ) - int( $y / 100 ) + int( $y / 4 );
50             }
51             else {
52 4         15 $j += int( ( $y + 4716 ) / 4 ) - 1181;
53             }
54 79         536 $j + 365 * $y + floor( 30.6001 * ( $m + 1 ) )
55             }
56              
57             sub jd2cal {
58 22     22 1 8640 my $jd = shift;
59 22         80 my %arg = (gregorian => 1, @_);
60              
61 22         111 my ( $f, $i ) = modf($jd - $J1900 + 0.5);
62 22 100 100     138 if ($arg{gregorian} && $i > -115860) {
63 17         76 my $a = floor($i / 36524.25 + 9.9835726e-1) + 14;
64 17         73 $i += 1 + $a - floor($a / 4);
65             }
66              
67 22         70 my $b = floor($i / 365.25 + 8.02601e-1);
68 22         65 my $c = $i - floor(365.25 * $b + 7.50001e-1) + 416;
69 22         59 my $g = floor($c / 30.6001);
70 22         67 my $da = $c - floor(30.6001 * $g) + $f;
71 22 100       69 my $mo = $g - ($g > 13.5 ? 13 : 1);
72 22 100       84 my $ye = $b + ($mo < 2.5 ? 1900 : 1899);
73 22         85 $ye, $mo, $da
74             }
75              
76             sub jd0 {
77 8     8 1 3597 my $j = shift;
78 8         44 floor( $j - 0.5 ) + 0.5;
79             }
80              
81             sub unix2jd {
82 3     3 1 4729 $JD_UNIX_EPOCH + $_[0] / $SEC_PER_DAY
83             }
84              
85             sub jd2unix {
86 3     3 1 6111 int( ($_[0] - $JD_UNIX_EPOCH) * $SEC_PER_DAY )
87             }
88              
89             sub _gmtime2jd {
90 7     7   61 cal2jd(
91             $_[5] + 1900,
92             $_[4] + 1,
93             $_[3] + ddd(@_[2, 1, 0]) / 24
94             )
95             }
96              
97              
98             sub jdnow {
99 0     0 1 0 _gmtime2jd(gmtime())
100             }
101              
102             sub jd2mjd {
103 3     3 1 8113 $_[0] - $J2000;
104             }
105              
106              
107             sub mjd2jd {
108 3     3 1 4667 $_[0] + $J2000;
109             }
110              
111             # converts Julian date to period in centuries since epoch
112             # Arguments:
113             # julian date
114             # julian date corresponding to the epoch start
115             sub _t {
116 1274     1274   2398 my ( $jd, $epoch ) = @_;
117 1274         3414 ( $jd - $epoch ) / 36525;
118             }
119              
120              
121             sub jd_cent {
122 1269     1269 1 6308 _t( $_[0], $J2000 );
123             }
124              
125              
126             sub t1900 {
127 5     5 1 451 _t( $_[0], $J1900 );
128             }
129              
130              
131             sub jd2gst {
132 4     4 1 6 my $jh = shift;
133 4         12 my $j0 = jd0($jh);
134 4         12 my $s0 = polynome( t1900($j0), 0.276919398, 100.0021359, 0.000001075 );
135 4         23 24 * ( frac($s0) + abs( $jh - $j0 ) * $SOLAR_TO_SIDEREAL );
136             }
137              
138             sub jd2lst {
139 4     4 1 6675 my ( $jd, $lon ) = @_;
140 4   50     24 $lon //= 0;
141 4         13 to_range( jd2gst($jd) - $lon / 15, 24 );
142             }
143              
144              
145             1;
146              
147             __END__
148              
149             =pod
150              
151             =encoding UTF-8
152              
153             =head1 NAME
154              
155             Astro::Montenbruck::Time - Time-related routines
156              
157             =head1 VERSION
158              
159             Version 0.01
160              
161             =head1 SYNOPSIS
162              
163             use Astro::Montenbruck::Time qw/:all/;
164              
165             # Convert Gregorian (new-style) date to old-style date
166             my $j = cal2jd(1799, 6, 6); # Standard Julian date of A.Pushkin's birthday
167             my $d = jd2cal($j, gregorian => 0) # (1799, 5, 25) = May 26, 1799.
168              
169             # Julian date in centuries since epoch 2000.0
170             my $t = jd_cent($j); # -2.0056810403833
171             ...
172              
173             =head1 DESCRIPTION
174              
175             Library of date/time manipulation routines for practical astronomy. Most of them
176             are based on so called I<Julian date (JD)>, which is the number of days elapsed
177             since mean UT noon of B<January 1st 4713 BC>. This system of time measurement is
178             widely adopted by the astronomers.
179              
180             =head2 JD and MJD
181              
182             Many routines use Modified Julian date, which starts at B<2000 January 0>
183             (2000 January 1.0) as the starting point.
184              
185             =head2 Civil year vs astronomical year
186              
187             There is disagreement between astronomers and historians about how to count the
188             years preceding the year 1. Astronomers generally use zero-based system. The
189             year before the year +1, is the year zero, and the year preceding the latter is
190             the year -1. The year which the historians call 585 B.C. is actually the year
191             -584.
192              
193             In this module all subroutines accepting year assume that B<there is year zero>.
194             Thus, the sequence of years is: C<BC -3, -2, -1, 0, 1, 2, 3, AD>.
195              
196             =head2 Date and Time
197              
198             Time is represented by fractional part of a day. For example, 7h30m UT
199             is C<(7 + 30 / 60) / 24 = 0.3125>.
200              
201             =head3 Gregorian calendar
202              
203             I<Civil calendar> in most cases means I<proleptic Gregorian calendar>. it is
204             assumed that Gregorian calendar started at Oct. 4, 1582, when it was first
205             adopted in several European countries. Many other countries still used the older
206             Julian calendar. In Soviet Russia, for instance, Gregorian system was accepted
207             on Jan 26, 1918. See:
208             L<https://en.wikipedia.org/wiki/Gregorian_calendar#Adoption_of_the_Gregorian_Calendar>
209              
210              
211             =head1 EXPORTED CONSTANTS
212              
213             =over
214              
215             =item * C<$SEC_PER_DAY> seconds per day (86400)
216              
217             =item * C<$SEC_PER_CEN> seconds per century (3155760000)
218              
219             =item * C<$J2000> Standard Julian date for start of epoch 2000,0 (2451545)
220              
221             =item * C<$J1900> Standard Julian date for start of epoch 1900,0 (2415020)
222              
223             =item * C<$GREGORIAN_START> Start of Gregorian calendar, YYYYMMDD (15821004)
224              
225             =item * C<$JD_UNIX_EPOCH> Standard Julian date for start of the Unix epoch
226              
227             =back
228              
229             =head1 EXPORTED FUNCTIONS
230              
231             =over
232              
233             =item * L</jd_cent($jd)>
234              
235             =item * L</after_gregorian($year, $month, $date)>
236              
237             =item * L</cal2jd($year, $month, $date)>
238              
239             =item * L</jd2cal($jd)>
240              
241             =item * L</jd0($jd)>
242              
243             =item * L</unix2jd($seconds)>
244              
245             =item * L</jd2unix($jd)>
246              
247             =item * L</jdnow()>
248              
249             =item * L</jd2mjd($jd)>
250              
251             =item * L</mjd2jd($mjd)>
252              
253             =item * L</jd_cent($jd)>
254              
255             =item * L</t1900($jd)>
256              
257              
258             =item * L</jd2dt($jd)>
259              
260             =item * L</jd2te($jd)>
261              
262             =item * L</jd2gst($jd)>
263              
264             =item * L</jd2lst($jd, $lng)>
265              
266             =back
267              
268             =head1 FUNCTIONS
269              
270             =head2 jd_cent($jd)
271              
272             Convert Standard Julian Date to centuries passed since epoch 2000.0
273              
274             =head2 after_gregorian($year, $month, $date, gregorian_start => $YYYYMMDD )
275              
276             Does the given date fall to period after Gregorian calendar?
277              
278             =head3 Positional Arguments
279              
280             =over
281              
282             =item * B<year> (astronomic, zero-based)
283              
284             =item * B<month> (1-12)
285              
286             =item * B<date> UTC date (1-31) with hours and minutes as decimal part
287              
288             =back
289              
290             =head3 Optional Named Arguments
291              
292             =over
293              
294             =item *
295              
296             B<gregorian_start> — start of Gregorian calendar. Default value is
297             B<15821004> If the date is Julian ("old style"), use C<undef> value.
298             To provide non-standard start of Gregorian calendar, provide a number
299             in format YYYYMMDDD, e.g. C<19180126> for Jan 26, 1918.
300              
301             =back
302              
303             =head3 Returns
304              
305             I<true> or I<false>=.
306              
307             =head2 cal2jd($year, $month, $date)
308              
309             Convert civil date/time to Standard Julian date.
310              
311             If C<gregorian_start> argument is not provided, it is assumed that this is a date
312             of I<Proleptic Gregorian calendar>, which started at Oct. 4, 1582.
313              
314             =head3 Positional Arguments:
315              
316             =over
317              
318             =item * B<year> (astronomic, zero-based)
319              
320             =item * B<month> (1-12)
321              
322             =item * B<date> UTC date (1-31) with hours and minutes as decimal part
323              
324             =back
325              
326             =head3 Optional Named Arguments
327              
328             =over
329              
330             =item *
331              
332             gregorian_start — start of Gregorian calendar. Default value is
333             B<15821004> If the date is Julian ("old style"), use C<undef> value.
334             To provide non-standard start of Gregorian calendar, provide a number
335             in format YYYYMMDDD, e.g. C<19180126> for Jan 26, 1918.
336              
337             =back
338              
339             =head3 Returns
340              
341             Standard Julian date
342              
343             =head2 jd2cal($jd)
344              
345             Convert Standard Julian date to civil date/time
346              
347             =head3 Positional Arguments
348              
349             Standard Julian Date
350              
351             =head3 Optional Named Arguments
352              
353             =over
354              
355             =item * gregorian — if i<true>, the result will be old-style (Julian) date
356              
357             =back
358              
359             =head3 Returns
360              
361             A list corresponding to the input values of L</cal2jd($year, $month, $date)> function.
362             The date is given in the proleptic Gregorian calendar system unless B<gregorian>
363             flag is set to I<true>.
364              
365             =head2 jd0($jd)
366              
367             Given Standard Julian Date, calculate Standard Julian date for midnight of the same date.
368              
369             =head2 unix2jd($seconds)
370              
371             Given Unix time, in seconds, convert it to Standard Julian date.
372              
373             =head2 jd2unix($jd)
374              
375             Given a Standard Julian Date, convert it to Unix time, in seconds since start of
376             Unix epoch.
377              
378             If JD falls before start of the epoch, result will be negative and thus, unusable
379             for Unix-specific functions like B<localtime()>.
380              
381             =head2 jdnow()
382              
383             Standard Julian date for the current moment.
384              
385             =head2 jd2mjd($jd)
386              
387             Standard to Modified Julian date.
388              
389             =head2 mjd2jd($mjd)
390              
391             Modified to Standard Julian date.
392              
393             =head2 jd_cent($jd)
394              
395             Given aI<Standard Julian date>, calculate time in centuries since epoch 2000.0.
396              
397             =head2 t1900($jd)
398              
399             Given a I<Standard Julian date>, calculate time in centuries since epoch 2000.0.
400              
401              
402             =head2 jd2gst($jd)
403              
404             Given I<Standard Julian date>, calculate I<True Greenwich Sidereal time>.
405              
406             =head2 jd2lst($jd, $lng)
407              
408             Givan I<Standard Julian date>, calculate true I<Local Sidereal time>.
409              
410             =head3 Arguments
411              
412             =over
413              
414             =item * $jd — Standard Julian date
415              
416             =item * $lng — Geographic longitude, negative for Eastern longitude, 0 by default
417              
418             =back
419              
420              
421             =head1 AUTHOR
422              
423             Sergey Krushinsky, C<< <krushi at cpan.org> >>
424              
425             =head1 LICENSE AND COPYRIGHT
426              
427             Copyright 2010-2019 Sergey Krushinsky.
428              
429             This program is free software; you can redistribute it and/or modify it
430             under the terms of either: the GNU General Public License as published
431             by the Free Software Foundation; or the Artistic License.
432              
433             See http://dev.perl.org/licenses/ for more information.
434              
435             =cut