File Coverage

blib/lib/DateTime/PP.pm
Criterion Covered Total %
statement 83 102 81.3
branch 12 32 37.5
condition 6 14 42.8
subroutine 13 15 86.6
pod n/a
total 114 163 69.9


line stmt bran cond sub pod time code
1             package DateTime::PP;
2              
3 1     1   7 use strict;
  1         2  
  1         34  
4 1     1   6 use warnings;
  1         2  
  1         183  
5              
6             our $VERSION = '1.60';
7              
8             ## no critic (Variables::ProhibitPackageVars)
9             $DateTime::IsPurePerl = 1;
10             ## use critic
11              
12             my @MonthLengths = ( 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 );
13              
14             my @LeapYearMonthLengths = @MonthLengths;
15             $LeapYearMonthLengths[1]++;
16              
17             my @EndOfLastMonthDayOfYear;
18             {
19             my $x = 0;
20             foreach my $length (@MonthLengths) {
21             push @EndOfLastMonthDayOfYear, $x;
22             $x += $length;
23             }
24             }
25              
26             my @EndOfLastMonthDayOfLeapYear = @EndOfLastMonthDayOfYear;
27             $EndOfLastMonthDayOfLeapYear[$_]++ for 2 .. 11;
28              
29             ## no critic (Subroutines::ProhibitUnusedPrivateSubroutines)
30             sub _time_as_seconds {
31 1     1   2 shift;
32 1         4 my ( $hour, $min, $sec ) = @_;
33              
34 1   50     6 $hour ||= 0;
35 1   50     6 $min ||= 0;
36 1   50     7 $sec ||= 0;
37              
38 1         16 my $secs = $hour * 3600 + $min * 60 + $sec;
39 1         2 return $secs;
40             }
41              
42             sub _rd2ymd {
43 1     1   3 my $class = shift;
44              
45 1     1   7 use integer;
  1         2  
  1         5  
46 1         3 my $d = shift;
47 1         2 my $rd = $d;
48              
49 1         2 my $yadj = 0;
50 1         3 my ( $c, $y, $m );
51              
52             # add 306 days to make relative to Mar 1, 0
53 1 50       4 if ( ( $d += 306 ) <= 0 ) {
54              
55             # avoid ambiguity in C division of negatives
56 0         0 $yadj = -( -$d / 146097 + 1 );
57 0         0 $d -= $yadj * 146097;
58             }
59              
60 1         3 $c = ( $d * 4 - 1 )
61             / 146097; # calc # of centuries $d is after 29 Feb of yr 0
62 1         3 $d -= $c * 146097 / 4; # (4 centuries = 146097 days)
63 1         3 $y = ( $d * 4 - 1 ) / 1461; # calc number of years into the century,
64 1         2 $d -= $y * 1461 / 4; # again March-based (4 yrs =~ 146[01] days)
65 1         13 $m = ( $d * 12 + 1093 )
66             / 367; # get the month (3..14 represent March through
67 1         3 $d -= ( $m * 367 - 1094 ) / 12; # February of following year)
68 1         5 $y += $c * 100 + $yadj * 400; # get the real year, which is off by
69             # one if month is January or February
70              
71 1 50       5 if ( $m > 12 ) {
72 1         2 ++$y;
73 1         2 $m -= 12;
74             }
75              
76 1 50       3 if ( $_[0] ) {
77 1         2 my $dow;
78              
79 1 50       16 if ( $rd < -6 ) {
80 0         0 $dow = ( $rd + 6 ) % 7;
81 0 0       0 $dow += $dow ? 8 : 1;
82             }
83             else {
84 1         3 $dow = ( ( $rd + 6 ) % 7 ) + 1;
85             }
86              
87 1         4 my $doy = $class->_end_of_last_month_day_of_year( $y, $m );
88              
89 1         2 $doy += $d;
90              
91 1         2 my $quarter;
92             {
93 1     1   188 no integer;
  1         2  
  1         5  
  1         2  
94 1         6 $quarter = int( ( 1 / 3.1 ) * $m ) + 1;
95             }
96              
97 1         12 my $qm = ( 3 * $quarter ) - 2;
98              
99 1         9 my $doq
100             = ( $doy - $class->_end_of_last_month_day_of_year( $y, $qm ) );
101              
102 1         6 return ( $y, $m, $d, $dow, $doy, $quarter, $doq );
103             }
104              
105 0         0 return ( $y, $m, $d );
106             }
107              
108             sub _ymd2rd {
109 28     28   38 shift; # ignore class
110              
111 1     1   141 use integer;
  1         2  
  1         3  
112 28         45 my ( $y, $m, $d ) = @_;
113 28         31 my $adj;
114              
115             # make month in range 3..14 (treat Jan & Feb as months 13..14 of
116             # prev year)
117 28 100       51 if ( $m <= 2 ) {
    50          
118 17         27 $y -= ( $adj = ( 14 - $m ) / 12 );
119 17         22 $m += 12 * $adj;
120             }
121             elsif ( $m > 14 ) {
122 0         0 $y += ( $adj = ( $m - 3 ) / 12 );
123 0         0 $m -= 12 * $adj;
124             }
125              
126             # make year positive (oh, for a use integer 'sane_div'!)
127 28 50       52 if ( $y < 0 ) {
128 0         0 $d -= 146097 * ( $adj = ( 399 - $y ) / 400 );
129 0         0 $y += 400 * $adj;
130             }
131              
132             # add: day of month, days of previous 0-11 month period that began
133             # w/March, days of previous 0-399 year period that began w/March
134             # of a 400-multiple year), days of any 400-year periods before
135             # that, and finally subtract 306 days to adjust from Mar 1, year
136             # 0-relative to Jan 1, year 1-relative (whew)
137              
138             $d
139 28         81 += ( $m * 367 - 1094 ) / 12
140             + $y % 100 * 1461 / 4
141             + ( $y / 100 * 36524 + $y / 400 )
142             - 306;
143             }
144              
145             sub _seconds_as_components {
146 1     1   2 shift;
147 1         5 my $secs = shift;
148 1         18 my $utc_secs = shift;
149 1   50     14 my $modifier = shift || 0;
150              
151 1     1   170 use integer;
  1         2  
  1         4  
152              
153 1         3 $secs -= $modifier;
154              
155 1         2 my $hour = $secs / 3600;
156 1         2 $secs -= $hour * 3600;
157              
158 1         2 my $minute = $secs / 60;
159              
160 1         2 my $second = $secs - ( $minute * 60 );
161              
162 1 50 33     5 if ( $utc_secs && $utc_secs >= 86400 ) {
163              
164             # there is no such thing as +3 or more leap seconds!
165 0 0       0 die "Invalid UTC RD seconds value: $utc_secs"
166             if $utc_secs > 86401;
167              
168 0         0 $second += $utc_secs - 86400 + 60;
169              
170 0         0 $minute = 59;
171              
172 0         0 $hour--;
173 0 0       0 $hour = 23 if $hour < 0;
174             }
175              
176 1         4 return ( $hour, $minute, $second );
177             }
178              
179             sub _end_of_last_month_day_of_year {
180 2     2   4 my $class = shift;
181              
182 2         5 my ( $y, $m ) = @_;
183 2         3 $m--;
184             return (
185 2 50       6 $class->_is_leap_year($y)
186             ? $EndOfLastMonthDayOfLeapYear[$m]
187             : $EndOfLastMonthDayOfYear[$m]
188             );
189             }
190              
191             sub _is_leap_year {
192 2     2   3 shift;
193 2         3 my $year = shift;
194              
195             # According to Bjorn Tackmann, this line prevents an infinite loop
196             # when running the tests under Qemu. I cannot reproduce this on
197             # Ubuntu or with Strawberry Perl on Win2K.
198 2 50 33     16 return 0
199             if $year == DateTime::INFINITY() || $year == DateTime::NEG_INFINITY();
200 2 50       12 return 0 if $year % 4;
201 0 0         return 1 if $year % 100;
202 0 0         return 0 if $year % 400;
203              
204 0           return 1;
205             }
206              
207 0     0     sub _day_length { DateTime::LeapSecond::day_length( $_[1] ) }
208              
209 0     0     sub _accumulated_leap_seconds { DateTime::LeapSecond::leap_seconds( $_[1] ) }
210              
211             my @subs = qw(
212             _time_as_seconds
213             _rd2ymd
214             _ymd2rd
215             _seconds_as_components
216             _end_of_last_month_day_of_year
217             _is_leap_year
218             _day_length
219             _accumulated_leap_seconds
220             );
221              
222             for my $sub (@subs) {
223             ## no critic (TestingAndDebugging::ProhibitNoStrict)
224 1     1   364 no strict 'refs';
  1         2  
  1         92  
225             *{ 'DateTime::' . $sub } = __PACKAGE__->can($sub);
226             }
227              
228             # This is down here so that _ymd2rd is available when it loads,
229             # because it will load DateTime::LeapSecond, which needs
230             # DateTime->_ymd2rd to be available when it is loading
231             require DateTime::PPExtra;
232              
233             1;