Thirty years of Easter Sundays, worked out by pure arithmetic.
easter.py · output · proof · check · try it in the playground
Easter moves around: it falls on the first Sunday after a church-defined “full moon” in spring, so it can land anywhere from late March to late April.
Long before computers, people found a way to get the date with nothing but whole-number arithmetic on the year. One famous recipe is the anonymous Gregorian algorithm (also known as Meeus/Jones/Butcher).
When is Easter Sunday in each year from 2021 to 2050?
implied_by(
computus(Year, [Month, Day]),
is_(A, Year % 19)
& is_(B, Year // 100)
& is_(C, Year % 100)
& is_(D, (19 * A + B - B // 4 - (B - (B + 8) // 25 + 1) // 3 + 15) % 30)
& is_(E, (32 + 2 * (B % 4) + 2 * (C // 4) - D - C % 4) % 7)
& is_(F, D + E - 7 * ((A + 11 * D + 22 * E) // 451) + 114)
& is_(Month, F // 31)
& is_(Day, F % 31 + 1),
)
// is whole-number division and % is the remainder. Computus is the
traditional name for computing the date of Easter.
implied_by(in_range(Low, High, Low), Low <= High)
implied_by(in_range(Low, High, N), (Low < High) & is_(Next, Low + 1) & in_range(Next, High, N))
implies(in_range(2021, 2050, Year) & computus(Year, Date), easter(Year, Date))
in_range counts from 2021 up to 2050, one year at a time. The last line
says: for every year in that range, the Easter date is what the recipe gives.
easter(2021, [4, 4])
easter(2022, [4, 17])
easter(2023, [4, 9])
easter(2024, [3, 31])
easter(2025, [4, 20])
easter(2026, [4, 5])
# …
easter(2050, [4, 10])
One line per year, 30 in all. [4, 4] means April 4; [3, 31] means
March 31.
Take 2021. The proof records every intermediate number:
easter rule, with Year = 2021.For later years, the proof also shows the counting: 2022 is in range because 2021 < 2050 and 2021 + 1 = 2022, and so on.
The checker re-does every sum itself rather than trusting the proof’s numbers.
Verdict: checked.
python -m peye examples/easter.py # the 30 dates
python -m peye --proof examples/easter.py # with every calculation
Or open it in the playground.
Change the range in the last line to in_range(2000, 2000, Year) and run
again: you get easter(2000, [4, 23]), April 23.
A centuries-old calendar recipe becomes a list of dates where each one comes with its own worked arithmetic, recomputed by an independent checker.