File Coverage

blib/lib/Date/Easter.pm
Criterion Covered Total %
statement 35 51 68.6
branch 8 12 66.6
condition 3 6 50.0
subroutine 6 8 75.0
pod 4 5 80.0
total 56 82 68.2


line stmt bran cond sub pod time code
1             # $Header: /cvsroot/date-easter/lib/Date/Easter.pm,v 1.15 2003/04/21 03:23:29 rbowen Exp $
2             package Date::Easter;
3              
4             =head1 NAME
5              
6             Date::Easter - Calculates Easter for any given year
7              
8             =head1 SYNOPSIS
9              
10             use Date::Easter;
11             ($month, $day) = julian_easter(1752);
12             ($month, $day) = easter(1753);
13             ($month, $day) = gregorian_easter(1753);
14             ($month, $day) = orthodox_easter(1823);
15              
16             =head1 DESCRIPTION
17              
18             Calculates Easter for a given year.
19              
20             easter() is, for the moment, an alias to gregorian_easter(), since
21             that's what most people use now. The thought was to somehow know which of the
22             other methods to call, that that proved to be rather sticky.
23              
24             =cut
25              
26 3     3   52222 use strict;
  3         5  
  3         114  
27 3     3   13 use vars qw($VERSION @ISA @EXPORT);
  3         3  
  3         180  
28 3     3   9230 use Time::Local;
  3         4279  
  3         1310  
29             require Exporter;
30              
31             @ISA = qw( Exporter );
32             @EXPORT = qw( julian_easter gregorian_easter orthodox_easter easter );
33             $VERSION = '1.22';
34              
35             =pod
36              
37             Date::Easter provides the following functions:
38              
39             =head2 julian_easter
40              
41             ( $month, $day ) = julian_easter( $year );
42              
43             Returns the month and day of easter in the given year, in the Julian
44             calendar.
45              
46             =cut
47              
48             sub julian_easter {
49 0     0 1 0 my ($year) = @_;
50 0         0 my ( $G, $I, $J, $L, $month, $day, );
51 0         0 $G = $year % 19;
52 0         0 $I = ( 19 * $G + 15 ) % 30;
53 0         0 $J = ( $year + int( $year / 4 ) + $I ) % 7;
54 0         0 $L = $I - $J;
55 0         0 $month = 3 + int( ( $L + 40 ) / 44 );
56 0         0 $day = $L + 28 - ( 31 * ( int( $month / 4 ) ) );
57 0         0 return ( $month, $day );
58             }
59              
60             =head2 gregorian_easter
61              
62             ( $month, $day ) = gregorian_easter( $year );
63              
64             Returns the month and day of easter in the given year, in the
65             Gregorian calendar, which is what most of the world uses.
66              
67             =cut
68              
69             sub gregorian_easter {
70 6     6 1 2650 my ($year) = @_;
71 6         7 my ( $G, $C, $H, $I, $J, $L, $month, $day, );
72 6         7 $G = $year % 19;
73 6         10 $C = int( $year / 100 );
74 6         14 $H = ( $C - int( $C / 4 ) - int( ( 8 * $C + 13 ) / 25 ) + 19 * $G + 15 ) % 30;
75 6         13 $I = $H - int( $H / 28 ) *
76             ( 1 - int( $H / 28 ) * int( 29 / ( $H + 1 ) ) * int( ( 21 - $G ) / 11 ) );
77 6         9 $J = ( $year + int( $year / 4 ) + $I + 2 - $C + int( $C / 4 ) ) % 7;
78 6         5 $L = $I - $J;
79 6         7 $month = 3 + int( ( $L + 40 ) / 44 );
80 6         7 $day = $L + 28 - ( 31 * int( $month / 4 ) );
81 6         13 return ( $month, $day );
82             }
83              
84             =head2 easter
85              
86             ( $month, $day ) = easter( $year );
87              
88             Returns the month and day of easter in the given year, in the
89             Gregorian calendar, which is what most of the world uses.
90              
91             =cut
92              
93 0     0 1 0 sub easter { return gregorian_easter(@_); }
94              
95             # sub orthodox_easter {{{
96              
97             =head2 orthodox_easter
98              
99             ( $month, $day ) = orthodox_easter( $year );
100              
101             Returns the month and day of easter in the given year, in the
102             Orthodox calendar.
103              
104             From code by Pascalis Ligdas, based on original code by
105             Apostolos Syropoulos
106              
107             =cut
108              
109              
110             sub orthodox_easter {
111 6     6 1 4108 my $year = shift;
112              
113 6 50       14 die "Invalid year for Gregorian calendar" if ($year < 1583);
114              
115             # Find the date of the Paschal Full Moon (based on Alexandrian computus)
116 6         13 my $epact = ( ( $year % 19 ) * 11 ) % 30;
117 6         4 my $fullmoon = 5 - $epact;
118 6 100       10 $fullmoon += 30 if $fullmoon < -10;
119              
120             # Convert from Julian to Gregorian calender
121 6         13 $fullmoon += int($year / 100) - int($year / 400) - 2;
122              
123 6         6 my $month = 4;
124 6 100       16 if ( $fullmoon > 30 ) {
    50          
125 1         1 $month = 5;
126 1         2 $fullmoon -= 30;
127             } elsif ( $fullmoon <= 0 ) {
128 0         0 $month = 3;
129 0         0 $fullmoon += 31;
130             }
131              
132             # Find the next Sunday
133 6         14 my $fullmoonday = dow( $fullmoon, $month, $year );
134 6         374 my $easter = $fullmoon + ( 7 - $fullmoonday );
135              
136 6 50 33     35 if ( $month == 3 && $easter > 31 ) {
    50 66        
137 0         0 $month++;
138 0         0 $easter -= 31;
139             } elsif ( $month == 4 && $easter > 30 ) {
140 0         0 $month++;
141 0         0 $easter -= 30;
142             }
143 6         13 return ( $month, $easter );
144             }
145              
146             #}}}
147              
148 6     6 0 18 sub dow { ( localtime( timelocal( 0, 0, 0, $_[0], $_[1] - 1, $_[2] ) ) )[6] }
149              
150             1;
151              
152             =head1 AUTHOR
153              
154             Rich Bowen
155              
156             =head1 To Do
157              
158             Since the dates that various countries switched to the Gregorian
159             calendar vary greatly, it's hard to figure out when to use
160             which method. Perhaps some sort of locale checking would be
161             cool?
162              
163             I need to test the Julian easter calculations, but I'm a little
164             confused as to the difference between the Orthodox Easter and the
165             Julian Easter. I need to read some more.
166              
167             The use of localtime and timelocal locks us into the epoch, which is a
168             rather silly limitation. Need to move to Date::DayOfWeek or other
169             module to calculate the day of the week. This should immediately make
170             the module usable back to the beginning of celebration of Easter.
171              
172             =head1 Other Comments
173              
174             Yes, Date::Manip already has code in it to do this. But Date::Manip
175             is very big, and rather slow. I needed something faster and
176             smaller, and did not need all that other stuff. And I have a real
177             interest in date calculations, so I thought this would be fun.
178             Date::Manip is a very cool module. I use it myself.
179              
180             See also http://www.pauahtun.org/CalendarFAQ/cal/node3.html
181             for more details on calculating Easter.
182              
183             And many thanks to Simon Cozens who provided me with the code for the
184             orthodox_easter function.
185              
186             The tests are taken from a table at
187             http://www.chariot.net.au/~gmarts/eastcalc.htm
188              
189             The script 'easter' is just a simple way to find out when easter falls
190             in a given year. Type 'easter' to find easter for this year, and 'easter
191             1983' to find when easter falls in 1983.
192              
193