File Coverage

blib/lib/Calendar/Any/Julian.pm
Criterion Covered Total %
statement 84 92 91.3
branch 21 34 61.7
condition 5 15 33.3
subroutine 18 18 100.0
pod 4 8 50.0
total 132 167 79.0


line stmt bran cond sub pod time code
1             package Calendar::Any::Julian;
2             {
3             $Calendar::Any::Julian::VERSION = '0.5';
4             }
5 6     6   24499 use Carp;
  6         13  
  6         546  
6 6     6   5770 use POSIX qw/ceil/;
  6         51334  
  6         41  
7 6     6   17008 use base 'Calendar::Any';
  6         15  
  6         4113  
8             my @MONTH_DAYS = (0,31,59,90,120,151,181,212,243,273,304,334,365);
9             our $default_format = "%D";
10              
11             sub MONTH_DAYS {
12 5     5 0 25 return @MONTH_DAYS;
13             }
14              
15             sub new {
16 45     45 1 131 my $_class = shift;
17 45   33     188 my $class = ref $_class || $_class;
18 45         66 my $self = {};
19 45         108 bless $self, $class;
20 45 50       101 if ( @_ ) {
21 45         52 my %arg;
22 45 100       253 if ( $_[0] =~ /-\D/ ) {
23 2         8 %arg = @_;
24             } else {
25 43 100       94 if ( scalar(@_) == 3 ) {
26 4         30 $arg{$_} = shift for qw(-month -day -year);
27             } else {
28 39         133 return $self->from_absolute(shift);
29             }
30             }
31 6         14 foreach ( qw(-month -day -year) ) {
32 18 50       289 $self->{substr($_, 1)} = $arg{$_} if exists $arg{$_};
33             }
34 6         31 $self->absolute_date();
35             }
36 6         19 return $self;
37             }
38              
39             sub from_absolute {
40 6     6   6249 use integer;
  6         64  
  6         31  
41 2     2 0 4 my $self = shift;
42 2         4 my $date = shift;
43 2         253 $self->{absolute} = $date;
44 2         4 $date++;
45 2         5 my $n4 = $date / 1461;
46 2         14 my $d0 = $date % 1461;
47 2         4 my $n1 = $d0 / 365;
48 2         4 my $day = $d0 % 365 + 1;
49 2         26 my $year = 4 * $n4 + $n1;
50 2         4 my $month;
51 2 50       8 if ( $n1==4 ) {
52 0         0 $month = 12;
53 0         0 $day = 31;
54             } else {
55 2         3 $year++;
56 2         20 $month = ceil($day/31);
57 2 50       16 my $leap = (_is_leap_year($year) ? 1 : 0);
58 2 50       11 while ($day > $MONTH_DAYS[$month] + ($month >1 ? $leap: 0)) {
59 2         6 $month++;
60             }
61 2 50       7 $day = $day-$MONTH_DAYS[$month-1]-($month>2?$leap:0);
62             }
63 2         4 $self->{year} = $year;
64 2         5 $self->{month} = $month;
65 2         3 $self->{day} = $day;
66 2         11 return $self;
67             }
68              
69             sub absolute_date {
70 6     6   1419 use integer;
  6         1409  
  6         24  
71 4     4 0 17 my $self = shift;
72 4 100       11 if ( exists $self->{absolute} ) {
73 2         9 return $self->{absolute};
74             }
75 2         8 $self->assert_date();
76 2         6 return $self->{absolute} = _absoulte_date($self->month, $self->day, $self->year);
77             }
78              
79             sub is_leap_year {
80 1     1 1 6 return _is_leap_year(shift->year);
81             }
82              
83             sub day_of_year {
84 6     6 1 23 my $self = shift;
85 6         22 return _day_of_year($self->month, $self->day, $self->year);
86             }
87              
88             sub last_day_of_month {
89 6     6 1 10 my $self = shift;
90 6         22 return _last_day_of_month($self->month, $self->year);
91             }
92              
93             sub assert_date {
94 6     6 0 10 my $self = shift;
95 6 50       36 if ( $self->year == 0 ) {
96 0         0 croak('Not a valid year: should not be zero in ' . ref $self);
97             }
98 6 50 33     33 if ( $self->month < 1 || $self->month > 12 ) {
99 0         0 confess(sprintf('Not a valid month %d: should from 1 to 12 for %s', $self->month, ref $self));
100             }
101 6 50 33     40 if ( $self->day < 1 || $self->day > $self->last_day_of_month() ) {
102 0         0 confess(sprintf('Not a valid day %d: should from 1 to %d in month %d %d for %s',
103             $self->day, $self->last_day_of_month, $self->month, $self->year, ref $self));
104             }
105             }
106              
107             #==========================================================
108             # Private functions
109             #==========================================================
110             sub _absoulte_date {
111 2     2   15 my ($month, $day, $year) = @_;
112 2         5 int(_day_of_year($month, $day, $year) + 365*($year-1) + ($year-1)/4 -2);
113             }
114              
115             sub _day_of_year {
116 6     6   2379 use integer;
  6         1403  
  6         23  
117 8     8   18 my ($month, $day, $year) = @_;
118 8         18 my $day_of_year = $day + 31 * ($month-1);
119 8 100       26 if ( $month > 2) {
120 5         11 $day_of_year -= (23 + 4*$month)/10;
121 5 50       12 if ( _is_leap_year($year) ) {
122 0         0 $day_of_year++;
123             }
124             }
125 8         47 return $day_of_year;
126             }
127              
128             sub _is_leap_year {
129 8     8   14 my $year = shift;
130 8 50       23 if ( $year < 0 ) {
131 0         0 $year = abs($year) - 1;
132             }
133 8         39 $year % 4 == 0
134             }
135              
136             sub _last_day_of_month {
137 6     6   13 my ($month, $year) = @_;
138 6 50 33     45 return unless $month>0 && $month<13;
139 6 50 33     34 if ( $month==2 && _is_leap_year($year) ) {
140 0         0 29;
141             } else {
142 6         46 $MONTH_DAYS[$month]-$MONTH_DAYS[$month-1];
143             }
144             }
145              
146             1;
147              
148             __END__