How to calculate the Easter date in PL/SQL

6

Ever wondered how they Easter date is determined? And, even more important, how it is to be maintained in you application. Manually updating the date every year is an option, but it’s always better to calculate it on the fly. It’s not easy because it depends on the age of the moon at january 1st and uses the moonyear cycle.

So, here’s some pl/sql which calculates Easter sunday for any given year:....

create or replace function bepaal_paasdatum( p_jaar in number default to_numbeR(to_char( sysdate, ‘yyyy’) )) return date is
  VolleMaan    Date;
  GuldenGetal  pls_Integer;
  SchrikkelDg  pls_Integer := 14;
  Epacta       pls_Integer;
  KritEpacta   pls_Integer;
begin
  /* first we calculate the "golden number" of the year; we divide the year with the years in a moonyear cycle (19), and add 1
      (see http://en.wikipedia.org/wiki/Golden_numbers)
      */
  Guldengetal := mod( p_jaar, 19 ) +1;
  /*
     epacta is the age of the moon at januari 1st
       */
  Epacta      := mod((GuldenGetal * 11 )- SchrikkelDg + 2, 30);
  /*
    calculate the full moons in a year
  */
  VolleMaan   := to_Date(’13-03-‘||to_char( p_jaar), ‘dd-mm-yyyy’ ) + 31 – Epacta;
  If (mod( p_jaar , 4) = 0 and mod(p_jaar, 100) != 0 ) or mod(p_jaar, 400) = 0
  Then
    VolleMaan := VolleMaan – 1;
  end if;
  –
  If VolleMaan < to_Date(’22-03-‘||to_char( p_jaar), ‘dd-mm-yyyy’ )
  Then
    If GuldenGetal > 11
    Then
      KritEpacta := 26;
    Else
      KritEpacta := 25;
    End If;
   
    If Epacta < KritEpacta
    Then
      VolleMaan := VolleMaan + 29;
    Else
      VolleMaan := VolleMaan + 30;
    End If;
  End If;
  vollemaan := vollemaan +1 ;
  while to_char(vollemaan, ‘d’) != 1 –zondag zoeken
  loop
    vollemaan := vollemaan + 1;
  end loop;
  — 
  return( VolleMaan   );
end;
/

The results: 

PATRICK> begin
  2   for i in 1990 .. 2010
  3  loop
  4  dbms_output.put_line( ‘jaar ‘||i||'; ‘|| bepaal_paasdatum(i));
  5  end loop;
  6  end;
  7  /
jaar 1990; 15-APR-90
jaar 1991; 31-MAR-91
jaar 1992; 19-APR-92
jaar 1993; 11-APR-93
jaar 1994; 03-APR-94
jaar 1995; 16-APR-95
jaar 1996; 07-APR-96
jaar 1997; 30-MAR-97
jaar 1998; 12-APR-98
jaar 1999; 04-APR-99
jaar 2000; 23-APR-00
jaar 2001; 15-APR-01
jaar 2002; 31-MAR-02
jaar 2003; 20-APR-03
jaar 2004; 11-APR-04
jaar 2005; 27-MAR-05
jaar 2006; 16-APR-06
jaar 2007; 08-APR-07
jaar 2008; 20-APR-08
jaar 2009; 12-APR-09
jaar 2010; 04-APR-10

PL/SQL procedure successfully completed.

PATRICK>

I’ve checked the dates against easter dates found on internet, and it seems right. Except…. the date for next year! Sources on internet mention March 23th, 2008, but my function returns April 20th.

I hate to say I have no clue where the problem is. So, if you plan to use my function you’ll either should find the bug or implement it after 2008! Some people suggested I have a real Easter Egg in my code….

Share.

About Author

6 Comments

  1. Anton Scheffer on

    I don’t like wordpress. it changes my quotes “‘”, it changes my formating and it cuts my text when I use a < sign.

    In the above comment you should add the following line
    < 10

  2. Anton Scheffer on

    You use the internet to check your values, but you can also use it for querying your values:

    [pre]

    select 2000 + level
    , cast( to_timestamp_tz( extractValue( HTTPURITYPE( ‘www.holidaywebservice.com/Holidays/GBSCT/Dates/GBSCTHolidayDates.asmx/GetEaster?year=’
    || to_char( 2000 + level )
    ).getXML()
    , ‘/dateTime’
    , ‘xmlns=”http://www.27seconds.com/Holidays/GBSCT/Dates/”‘
    )
    , ‘YYYY-MM-DD”T”HH24:MI:SS.FF7TZH:TZM’
    ) as date
    )
    from dual connect by level