File Coverage

blib/lib/Date/Julian/Simple.pm
Criterion Covered Total %
statement 67 85 78.8
branch 15 34 44.1
condition 4 17 23.5
subroutine 18 20 90.0
pod 8 12 66.6
total 112 168 66.6


line stmt bran cond sub pod time code
1             package Date::Julian::Simple;
2              
3             $Date::Julian::Simple::VERSION = '0.15';
4             $Date::Julian::Simple::AUTHORITY = 'cpan:MANWAR';
5              
6             =head1 NAME
7              
8             Date::Julian::Simple - Represents Julian date.
9              
10             =head1 VERSION
11              
12             Version 0.15
13              
14             =cut
15              
16 2     2   178807 use 5.006;
  2         15  
17 2     2   1248 use Data::Dumper;
  2         14448  
  2         143  
18 2     2   1035 use POSIX qw/floor/;
  2         13282  
  2         10  
19 2     2   3934 use Time::localtime;
  2         12792  
  2         116  
20 2     2   1025 use Date::Exception::InvalidDay;
  2         183135  
  2         70  
21              
22 2     2   15 use Moo;
  2         4  
  2         8  
23 2     2   625 use namespace::autoclean;
  2         4  
  2         14  
24              
25 2     2   151 use overload q{""} => 'as_string', fallback => 1;
  2         3  
  2         15  
26              
27             =head1 DESCRIPTION
28              
29             Represents the Julian date.
30              
31             =cut
32              
33             our $MJD = 2400000.5;
34              
35             our $JULIAN_MONTHS = [
36             undef,
37             qw(January February March April May June
38             July August September October November December)
39             ];
40              
41             our $JULIAN_DAYS = [
42             qw(Sunday Monday Tuesday Wednesday Thursday Friday Saturday)
43             ];
44              
45             our $JULIAN_MONTH_DAYS = [
46             qw(31 28 31 30 31 30
47             31 31 30 31 30 31)
48             ];
49              
50             has julian_epoch => (is => 'ro', default => sub { 1721423.5 });
51             has days => (is => 'ro', default => sub { $JULIAN_DAYS });
52             has months => (is => 'ro', default => sub { $JULIAN_MONTHS });
53              
54             has year => (is => 'rw', predicate => 1);
55             has month => (is => 'rw', predicate => 1);
56             has day => (is => 'rw', predicate => 1);
57              
58             with 'Date::Utils';
59              
60             sub BUILD {
61 3     3 0 20 my ($self) = @_;
62              
63 3 50 33     28 if ($self->has_year && $self->has_month && $self->has_day) {
      33        
64 3         13 $self->validate_year($self->year);
65 3         63 $self->validate_month($self->month);
66 3 50       61 if ($self->is_leap_year($self->year)) {
67 0         0 my $day = $self->day;
68 0         0 my @caller = caller(0);
69 0 0       0 @caller = caller(2) if $caller[3] eq '(eval)';
70              
71 0 0       0 return if ($self->month != 2);
72              
73 0 0 0     0 Date::Exception::InvalidDay->throw({
    0 0        
      0        
74             method => __PACKAGE__."::validate_day",
75             message => sprintf("ERROR: Invalid day [%s].", defined($day)?($day):('')),
76             filename => $caller[1],
77             line_number => $caller[2] })
78             unless (defined($day) && ($day =~ /^\d+$/) && ($day >= 1) && ($day <= 29));
79             }
80             else {
81 3         10 $self->validate_day($self->day);
82             }
83             }
84             else {
85 0         0 my $today = localtime;
86 0         0 my $year = $today->year + 1900;
87 0         0 my $month = $today->mon + 1;
88 0         0 my $day = $today->mday;
89 0         0 $self->year($year);
90 0         0 $self->month($month);
91 0         0 $self->day($day);
92             }
93             }
94              
95             =head1 SYNOPSIS
96              
97             use strict; use warnings;
98             use Date::Julian::Simple;
99              
100             # prints today's Julian date.
101             print Date::Julian::Simple->new, "\n";
102              
103             =head1 METHODS
104              
105             =head2 to_julian()
106              
107             Returns julian day equivalent of the Julian date.
108              
109             =cut
110              
111             sub to_julian {
112 3     3 1 903 my ($self, $year, $month, $day) = @_;
113              
114 3 50       13 $day = $self->day unless defined $day;
115 3 50       9 $month = $self->month unless defined $month;
116 3 50       9 $year = $self->year unless defined $year;
117              
118             # Adjust negative common era years to the zero-based notation we use.
119 3 50       11 if ($year < 1) {
120 0         0 $year++;
121             }
122              
123             # Algorithm as given in Meeus, Astronomical Algorithms, Chapter 7, page 61.
124 3 50       8 if ($month <= 2) {
125 3         5 $year--;
126 3         6 $month += 12;
127             }
128              
129 3         42 return ((floor((365.25 * ($year + 4716))) + floor((30.6001 * ($month + 1))) + $day) - 1524.5);
130             }
131              
132             =head2 to_modified_julian()
133              
134             Returns modified julian day equivalent of the Julian date.
135              
136             =cut
137              
138             sub to_modified_julian {
139 0     0 1 0 my ($self, $year, $month, $day) = @_;
140              
141 0         0 return $self->to_julian($year, $month, $day) - $MJD;
142             }
143              
144             =head2 from_julian($julian_day)
145              
146             Returns Julian date as an object of type L equivalent of the
147             C<$julian_day>.
148              
149             =cut
150              
151             sub from_julian {
152 2     2 1 1674 my ($self, $julian_day) = @_;
153              
154 2         3 $julian_day += 0.5;
155 2         8 my $a = floor($julian_day);
156 2         5 my $b = $a + 1524;
157 2         6 my $c = floor(($b - 122.1) / 365.25);
158 2         5 my $d = floor(365.25 * $c);
159 2         5 my $e = floor(($b - $d) / 30.6001);
160              
161 2 50       9 my $month = floor(($e < 14) ? ($e - 1) : ($e - 13));
162 2 50       8 my $year = floor(($month > 2) ? ($c - 4716) : ($c - 4715));
163 2         7 my $day = $b - $d - floor(30.6001 * $e);
164              
165             # If year is less than 1, subtract one to convert from
166             # a zero based date system to the common era system in
167             # which the year -1 (1 B.C.E) is followed by year 1 (1 C.E)
168 2 50       8 if ($year < 1) {
169 0         0 $year--;
170             }
171              
172 2         53 return Date::Julian::Simple->new({ year => $year, month => $month, day => $day });
173             }
174              
175             =head2 from_modified_julian($modified_julian_day)
176              
177             Returns Julian date as an object of type L equivalent of the
178             C<$modified_julian_day>.
179              
180             =cut
181              
182             sub from_modified_julian {
183 0     0 1 0 my ($self, $modified_julian_day) = @_;
184              
185 0         0 return $self->from_julian($modified_julian_day + $MJD);
186             }
187              
188             =head2 to_gregorian()
189              
190             Returns Gregorian date as list (yyyy,mm,dd) equivalent of the Julian date.
191              
192             =cut
193              
194             sub to_gregorian {
195 1     1 1 518 my ($self) = @_;
196              
197 1         3 return $self->julian_to_gregorian($self->to_julian);
198             }
199              
200             =head2 from_gregorian($year, $month, $day)
201              
202             Returns Julian date as an object of type L equivalent of the
203             given Gregorian date C<$year>, C<$month> and C<$day>.
204              
205             =cut
206              
207             sub from_gregorian {
208 1     1 1 620 my ($self, $year, $month, $day) = @_;
209              
210 1         6 $self->validate_date($year, $month, $day);
211 1         58 return $self->from_julian($self->gregorian_to_julian($year, $month, $day));
212             }
213              
214             =head2 day_of_week()
215              
216             Returns day of the week, starting 0 for Sunday, 1 for Monday and so on.
217              
218             +-------+-------------------------------------------------------------------+
219             | Index | English Name |
220             +-------+-------------------------------------------------------------------+
221             | 0 | Sunday |
222             | 1 | Monday |
223             | 2 | Tuesday |
224             | 3 | Wednesday |
225             | 4 | Thursday |
226             | 5 | Friday |
227             | 6 | Saturday |
228             +-------+-------------------------------------------------------------------+
229              
230             =cut
231              
232             sub day_of_week {
233 1     1 1 3 my ($self) = @_;
234              
235 1         4 return $self->jwday($self->to_julian);
236             }
237              
238             =head2 is_leap_year($year)
239              
240             Returns 0 or 1 if the given Julian year C<$year> is a leap year or not.
241              
242             =cut
243              
244             sub is_leap_year {
245 13     13 1 1562 my ($self, $year) = @_;
246              
247 13   100     83 return (($year % 4) == (($year > 0) ? 0 : 3)) || 0;
248             }
249              
250             sub days_in_year {
251 3     3 0 7 my ($self, $year) = @_;
252              
253 3 100       9 ($self->is_leap_year($year))
254             ?
255             (return 366)
256             :
257             (return 365);
258             }
259              
260             sub days_in_month_year {
261 4     4 0 10 my ($self, $month, $year) = @_;
262              
263 4 100       9 if ($self->is_leap_year($year)) {
264 2 50       11 return 29 if ($month == 2);
265             }
266              
267 2         17 return $JULIAN_MONTH_DAYS->[$month-1];
268             }
269              
270             sub as_string {
271 1     1 0 32 my ($self) = @_;
272              
273 1         7 return sprintf("%d, %s %d", $self->day, $self->get_month_name, $self->year);
274             }
275              
276             =head1 AUTHOR
277              
278             Mohammad S Anwar, C<< >>
279              
280             =head1 REPOSITORY
281              
282             L
283              
284             =head1 SEE ALSO
285              
286             =over 4
287              
288             =item L
289              
290             =item L
291              
292             =item L
293              
294             =item L
295              
296             =item L
297              
298             =item L
299              
300             =back
301              
302             =head1 BUGS
303              
304             Please report any bugs / feature requests to C,
305             or through the web interface at L.
306             I will be notified, and then you'll automatically be notified of progress on your
307             bug as I make changes.
308              
309             =head1 SUPPORT
310              
311             You can find documentation for this module with the perldoc command.
312              
313             perldoc Date::Julian::Simple
314              
315             You can also look for information at:
316              
317             =over 4
318              
319             =item * RT: CPAN's request tracker
320              
321             L
322              
323             =item * AnnoCPAN: Annotated CPAN documentation
324              
325             L
326              
327             =item * CPAN Ratings
328              
329             L
330              
331             =item * Search CPAN
332              
333             L
334              
335             =back
336              
337             =head1 LICENSE AND COPYRIGHT
338              
339             Copyright (C) 2017 Mohammad S Anwar.
340              
341             This program is free software; you can redistribute it and / or modify it under
342             the terms of the the Artistic License (2.0). You may obtain a copy of the full
343             license at:
344              
345             L
346              
347             Any use, modification, and distribution of the Standard or Modified Versions is
348             governed by this Artistic License.By using, modifying or distributing the Package,
349             you accept this license. Do not use, modify, or distribute the Package, if you do
350             not accept this license.
351              
352             If your Modified Version has been derived from a Modified Version made by someone
353             other than you,you are nevertheless required to ensure that your Modified Version
354             complies with the requirements of this license.
355              
356             This license does not grant you the right to use any trademark, service mark,
357             tradename, or logo of the Copyright Holder.
358              
359             This license includes the non-exclusive, worldwide, free-of-charge patent license
360             to make, have made, use, offer to sell, sell, import and otherwise transfer the
361             Package with respect to any patent claims licensable by the Copyright Holder that
362             are necessarily infringed by the Package. If you institute patent litigation
363             (including a cross-claim or counterclaim) against any party alleging that the
364             Package constitutes direct or contributory patent infringement,then this Artistic
365             License to you shall terminate on the date that such litigation is filed.
366              
367             Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND
368             CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED
369             WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
370             NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL LAW. UNLESS
371             REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT,
372             INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE
373             OF THE PACKAGE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
374              
375             =cut
376              
377             1; # End of Date::Julian::Simple