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