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
|
|
|
|
|
|
|
|