File Coverage

blib/lib/Date/Easter.pm
Criterion Covered Total %
statement 37 51 72.5
branch 7 10 70.0
condition 6 12 50.0
subroutine 6 8 75.0
pod 4 5 80.0
total 60 86 69.7


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   70692 use strict;
  3         7  
  3         138  
27 3     3   16 use vars qw($VERSION @ISA @EXPORT);
  3         5  
  3         261  
28 3     3   2829 use Time::Local;
  3         6123  
  3         1778  
29             require Exporter;
30              
31             @ISA = qw( Exporter );
32             @EXPORT = qw( julian_easter gregorian_easter orthodox_easter easter );
33             $VERSION = '1.21';
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 3845 my ($year) = @_;
71 6         10 my ( $G, $C, $H, $I, $J, $L, $month, $day, );
72 6         9 $G = $year % 19;
73 6         15 $C = int( $year / 100 );
74 6         17 $H = ( $C - int( $C / 4 ) - int( ( 8 * $C ) / 25 ) + 19 * $G + 15 ) % 30;
75 6         16 $I = $H - int( $H / 28 ) *
76             ( 1 - int( $H / 28 ) * int( 29 / ( $H + 1 ) ) * int( ( 21 - $G ) / 11 ) );
77 6         13 $J = ( $year + int( $year / 4 ) + $I + 2 - $C + int( $C / 4 ) ) % 7;
78 6         10 $L = $I - $J;
79 6         9 $month = 3 + int( ( $L + 40 ) / 44 );
80 6         8 $day = $L + 28 - ( 31 * int( $month / 4 ) );
81 6         20 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             sub orthodox_easter {
110              
111 6     6 1 4353 my $year = shift;
112 6         14 my $epakti = ( ( ( $year - 2 ) % 19 ) * 11 ) % 30;
113 6         8 my $month;
114 6 100       14 if ( $epakti > 23 ) { $month = 4; }
  1         2  
115 5         6 else { $month = 3; }
116 6         9 my $fullmoon = 44 - $epakti + 13;
117              
118 6 100 66     42 if ( ( $month == 4 ) && ( $fullmoon > 30 ) ) {
    50 33        
119 1         2 $month++;
120 1         2 $fullmoon -= 30;
121             } elsif ( ( $month == 3 ) && ( $fullmoon > 31 ) )
122             {
123 5         6 $month++;
124 5         8 $fullmoon -= 31;
125             }
126 6         11 my $fullmoonday = dow( $fullmoon, $month, $year );
127 6         474 my $easter = $fullmoon + ( 7 - $fullmoonday );
128              
129 6 50 33     34 if ( ( $month == 3 ) && ( $easter > 31 ) ) {
    50 66        
130 0         0 $month++;
131 0         0 $easter -= 31;
132             } elsif ( ( $month == 4 ) && ( $easter > 30 ) )
133             {
134 0         0 $month++;
135 0         0 $easter -= 30;
136             }
137 6         18 return ( $month, $easter );
138             }
139             #}}}
140              
141 6     6 0 24 sub dow { ( localtime( timelocal( 0, 0, 0, $_[0], $_[1] - 1, $_[2] ) ) )[6] }
142              
143             1;
144              
145             =head1 AUTHOR
146              
147             Rich Bowen
148              
149             =head1 To Do
150              
151             Since the dates that various countries switched to the Gregorian
152             calendar vary greatly, it's hard to figure out when to use
153             which method. Perhaps some sort of locale checking would be
154             cool?
155              
156             I need to test the Julian easter calculations, but I'm a little
157             confused as to the difference between the Orthodox Easter and the
158             Julian Easter. I need to read some more.
159              
160             The use of localtime and timelocal locks us into the epoch, which is a
161             rather silly limitation. Need to move to Date::DayOfWeek or other
162             module to calculate the day of the week. This should immediately make
163             the module usable back to the beginning of celebration of Easter.
164              
165             =head1 Other Comments
166              
167             Yes, Date::Manip already has code in it to do this. But Date::Manip
168             is very big, and rather slow. I needed something faster and
169             smaller, and did not need all that other stuff. And I have a real
170             interest in date calculations, so I thought this would be fun.
171             Date::Manip is a very cool module. I use it myself.
172              
173             See also http://www.pauahtun.org/CalendarFAQ/cal/node3.html
174             for more details on calculating Easter.
175              
176             And many thanks to Simon Cozens who provided me with the code for the
177             orthodox_easter function.
178              
179             The tests are taken from a table at
180             http://www.chariot.net.au/~gmarts/eastcalc.htm
181              
182             The script 'easter' is just a simple way to find out when easter falls
183             in a given year. Type 'easter' to find easter for this year, and 'easter
184             1983' to find when easter falls in 1983.
185              
186