create procedure lib_date_easter_of_year (
ofyear smallint,
method smallint)
returns (
easter_date date)
as
declare variable easter_day smallint;
declare variable easter_month smallint;
declare variable yd smallint;
declare variable ym smallint;
declare variable a smallint;
declare variable b smallint;
declare variable c smallint;
declare variable d smallint;
declare variable e smallint;
declare variable t smallint;
begin
/*
Date Calculation of Easter Sunday
Algorithm by Ron Mallen - http://www.assa.org.au/edm.html
Method: 1 Original (calculation based on the Julian calendar,
valid for years 326 ff.)
2 Orthodox ([1] converted to the equivalent Gregorian date,
valid for years 1583 ... 4099)
3 Western (revised calculation based on [2],
valid for years 1583 ... 4099)
*/
easter_date = null;
if ( ( (method = 1)
and (326 <= ofyear))
or ( (method between 2 and 3)
and (ofyear between 1583 and 4099)))
then
begin
yd = ofyear / 100;
execute procedure lib_math_mod :ofyear, 19 returning_values :ym;
if (method between 1 and 2)
then
begin
execute procedure lib_math_mod 225 - (11 * :ym), 30 returning_values :a;
a = a + 21;
execute procedure lib_math_mod :a - 19, 7 returning_values :b;
execute procedure lib_math_mod 40 - :yd, 7 returning_values :c;
execute procedure lib_math_mod :ofyear, 100 returning_values :t;
execute procedure lib_math_mod (:t / 4) + :t, 7 returning_values :d;
execute procedure lib_math_mod 20 - :b - :c - :d, 7 returning_values :e;
e = e + 1;
easter_day = a + e;
if (method = 2)
then
begin
t = 10;
if (1600 < ofyear)
then
t = t + yd - 16 - ((yd - 16) / 4);
easter_day = easter_day + t;
end
end
if (method = 3)
then
begin
t = ((yd - 15 ) / 2) + 202 - (11 * ym);
if (yd in (21, 24, 25, 27, 28, 29, 30, 31, 32, 34, 35, 38))
then
t = t - 1;
if (yd in (33, 36, 37, 39, 40))
then
t = t - 2;
execute procedure lib_math_mod :t, 30 returning_values :t;
a = t + 21;
if (t = 29)
then
a = a - 1;
if ( (t = 28)
and (10 < ym))
then
a = a - 1;
execute procedure lib_math_mod :a - 19, 7 returning_values :b;
execute procedure lib_math_mod 40 - :yd, 4 returning_values :c;
if (c = 3)
then
c = c + 1;
if (1 < c)
then
c = c + 1;
execute procedure lib_math_mod :ofyear, 100 returning_values :t;
execute procedure lib_math_mod (:t / 4) + :t, 7 returning_values :d;
execute procedure lib_math_mod 20 - :b - :c - :d, 7 returning_values :e;
e = e + 1;
easter_day = a + e;
end
if (61 < easter_day)
then
begin
easter_day = easter_day - 61;
easter_month = 5;
end
else
if (31 < easter_day)
then
begin
easter_day = easter_day - 31;
easter_month = 4;
end
else
easter_month = 3;
easter_date = cast( ofyear || '-' || easter_month || '-' || easter_day as date);
end
suspend;
end