Tuesday, March 25, 2008

### Computus

This week I got involved on a small discussion about a system at office that would require a holidays' database, in order to calculate the next available date to establish pay dates for invoices.

There were several talks about the proper ways to do this, and because I had other projects on my task list now I could not implement the agreed solution (which I don't quite remember now).

But...

During this discussions I did a little research about holidays.

Most holidays are a fixed event, i.e., they don't move around on the calendar. For instance, everybody knows that December 25th is Christmas Day.

However, there are several other holidays that are not so simple to nail down.

Take Easter Sunday for instance. It can be any Sunday between March 22nd and April 25th.

A quick look at Wikipedia gives us a plethora of methods to calculate the Easter Sunday. Using tables, adjusts and several calculations.

The function below uses one of this methods. Called the Butcher's Algorithm.

In my little research I found that this algorithm, according to some sources, was devised in 1876 (they tend to agree that it was first published on Butcher's Ecclesiastical Calendar).

With the date of Easter established with a few more additions and subtractions we can calculate most of the movable holidays.

 Day Add Ash Wednesday -46 Palm Sunday -7 Good Friday -2 Corpus Christi +60

`Public Function GetEaster(ByVal year As Integer) As Date    If (year < 1583) Then        Throw New _          ArgumentOutOfRangeException("year", _                   "Year must be after 1583")    End If    Dim a As Integer = year Mod 19    Dim b As Integer = year \ 100    Dim c As Integer = year Mod 100    Dim d As Integer = b \ 4    Dim e As Integer = b Mod 4    Dim f As Integer = (b + 8) \ 25    Dim g As Integer = (b - f + 1) \ 3    Dim h As Integer = (19 * a + b - d - g + 15) Mod 30    Dim i As Integer = c \ 4    Dim k As Integer = c Mod 4    Dim L As Integer = (32 + 2 * e + 2 * i - h - k) Mod 7    Dim m As Integer = (a + 11 * h + 22 * L) \ 451    Dim p As Integer = (h + L - 7 * m + 114)    Return (New Date(year, p \ 31, (p Mod 31) + 1))End Function`