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

Comments