Files
typikon/src/paschalion.rs
T

143 lines
4.6 KiB
Rust
Raw Normal View History

2026-09-18 11:13:10 -04:00
//! Pascha, and the movable cycle that hangs off it.
//!
//! Two reckonings are in use. The **Julian Paschalion** is what nearly every
//! Orthodox Church keeps: the old computus, worked in the Julian calendar and
//! then read off onto a civil date. The **Gregorian Paschalion** is the Western
//! one, kept by the Finnish Orthodox Church and by most Byzantine Catholics.
//!
//! Neither is a variant of the other. They are separate tables that happen to
//! agree in some years, 2025 falls on 20 April by both, and can diverge by as
//! much as five weeks.
use crate::calendars::{Date, JulianDate};
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum Paschalion {
Julian,
Gregorian,
}
/// Pascha by the Julian Paschalion, as a civil (Gregorian) date.
///
/// Meeus' Julian algorithm yields a date in the *Julian* calendar, which is
/// then read onto the civil one. The type system enforces that step here: the
/// algorithm builds a `JulianDate`, and only `to_civil` produces a `Date`.
pub fn julian_pascha(year: i32) -> Date {
let a = year % 4;
let b = year % 7;
let c = year % 19;
let d = (19 * c + 15) % 30;
let e = (2 * a + 4 * b - d + 34) % 7;
let month = ((d + e + 114) / 31) as u32;
let day = (((d + e + 114) % 31) + 1) as u32;
JulianDate { year, month, day }.to_civil()
}
/// Pascha by the Gregorian Paschalion, the Western computus.
pub fn gregorian_pascha(year: i32) -> Date {
let a = year % 19;
let b = year / 100;
let c = year % 100;
let d = b / 4;
let e = b % 4;
let g = (8 * b + 13) / 25;
let h = (19 * a + b - d - g + 15) % 30;
let i = c / 4;
let k = c % 4;
let l = (32 + 2 * e + 2 * i - h - k) % 7;
let m = (a + 11 * h + 19 * l) / 433;
let month = ((h + l - 7 * m + 90) / 25) as u32;
let day = ((h + l - 7 * m + 33 * month as i32 + 19) % 32) as u32;
Date::from_ymd(year, month, day).expect("computus yields a real date")
}
pub fn pascha(year: i32, p: Paschalion) -> Date {
match p {
Paschalion::Julian => julian_pascha(year),
Paschalion::Gregorian => gregorian_pascha(year),
}
}
/// Every movable date the calendar needs, keyed off Pascha.
///
/// All of these are counted in real days from Pascha, so they are civil dates
/// already and need no calendar conversion: the distance from Pascha to
/// Pentecost is fifty days in every reckoning.
///
/// A struct rather than a map, so a typo in a key is a compile error instead
/// of a silent `None` at the far end of the program.
#[derive(Clone, Copy, Debug)]
pub struct Movables {
pub pascha: Date,
// the Triodion, counted backwards
pub publican_pharisee: Date,
pub prodigal_son: Date,
pub meatfare: Date,
pub cheesefare: Date,
pub cheesefare_week_start: Date,
pub clean_monday: Date,
pub orthodoxy_sunday: Date,
pub gregory_palamas: Date,
pub cross_veneration: Date,
pub john_climacus: Date,
pub mary_of_egypt: Date,
/// The Forty Days end here, on the Friday before Lazarus Saturday.
pub great_fast_end: Date,
pub lazarus_saturday: Date,
pub palm_sunday: Date,
pub great_week_start: Date,
pub great_thursday: Date,
pub great_friday: Date,
pub holy_saturday: Date,
// the Pentecostarion, counted forwards
pub bright_week_end: Date,
pub thomas_sunday: Date,
pub myrrhbearers: Date,
pub midfeast: Date,
pub ascension: Date,
pub fathers_first_council: Date,
pub pentecost: Date,
pub pentecost_week_end: Date,
pub all_saints: Date,
/// The Apostles' Fast begins the Monday after All Saints. Its end is a
/// fixed ecclesiastical date, so the jurisdiction resolves that.
pub apostles_start: Date,
}
pub fn movable_cycle(year: i32, p: Paschalion) -> Movables {
let d = pascha(year, p);
Movables {
pascha: d,
publican_pharisee: d - 70,
prodigal_son: d - 63,
meatfare: d - 56,
cheesefare_week_start: d - 55,
cheesefare: d - 49,
clean_monday: d - 48,
orthodoxy_sunday: d - 42,
gregory_palamas: d - 35,
cross_veneration: d - 28,
john_climacus: d - 21,
mary_of_egypt: d - 14,
great_fast_end: d - 9,
lazarus_saturday: d - 8,
palm_sunday: d - 7,
great_week_start: d - 6,
great_thursday: d - 3,
great_friday: d - 2,
holy_saturday: d - 1,
bright_week_end: d + 6,
thomas_sunday: d + 7,
myrrhbearers: d + 14,
midfeast: d + 24,
ascension: d + 39,
fathers_first_council: d + 42,
pentecost: d + 49,
pentecost_week_end: d + 55,
all_saints: d + 56,
apostles_start: d + 57,
}
}