日本語 · English

Computing Easter as a schedule expression — zero-data Computus

Translated from the canonical Japanese page recipes/easter-schedule.md.

Easter is a movable feast — “the first Sunday after the first full moon on or after the spring equinox” — and recurrence-rule languages have uniformly given up on it. In Kairos it is eight lines of pure arithmetic with zero external data.

What happens with existing recurrence rules

Writing it in Kairos

Transcribe the Western-church (Gregorian) Computus — the Anonymous Gregorian algorithm — directly into value functions. Only div, mod, and projections (year, month, ordinalIn); no dependency on calendar data:

# eval: 2024-01-01..2029-01-01 tz: UTC
premise W {
  calendar-system: Gregorian
  tz: "UTC"
  wkst: Mon
}
@W
a = y => y mod 19
b = y => y div 100
h = y => (19*a(y) + b(y) - b(y) div 4 - (b(y) - (b(y)+8) div 25 + 1) div 3 + 15) mod 30
l = y => (32 + 2*(b(y) mod 4) + 2*((y mod 100) div 4) - h(y) - (y mod 100) mod 4) mod 7
m = y => (a(y) + 11*h(y) + 22*l(y)) div 451
eMonth = y => (h(y) + l(y) - 7*m(y) + 114) div 31
eDay   = y => ((h(y) + l(y) - 7*m(y) + 114) mod 31) + 1
everyDay |> filter(d => month(d) == eMonth(year(d)) and ordinalIn(day, month, d) == eDay(year(d)))
#=> 2024-03-31 2025-04-20 2026-04-05 2027-03-28 2028-04-16

All five years match the publicly known Easter dates. Related days such as Good Friday and Easter Monday are just shift(±n, unit: day) applied to this stream — being able to feed a derived stream into the next rule (closure) is what lets the whole family of related movable feasts grow one definition at a time.

Scope, stated explicitly

This is the Western-church, Gregorian-calendar computation. The Orthodox Easter (based on the Julian calendar) is different arithmetic, and in either tradition the official liturgical calendar is upstream — this recipe transcribes a rule; it does not replace the authority that sets the dates. Days decided by official announcement rather than by rule (national holiday practice, for example) are properly handled by bringing in data (external, covering:/asof:), not by arithmetic.

Try it in your browser

Run it in the Playground — widen the evaluation range to check any year.