2026-09-18 11:13:10 -04:00
//! Who keeps which calendar, and by whose rule.
//!
//! A jurisdiction is four independent choices, and conflating any two of them
//! is how calendar code usually goes wrong:
//!
//! - **paschalion**: which table gives Pascha
//! - **menologion**: which calendar the fixed feasts are read on
//! - **rule**: which fasting discipline is kept
//! - **menaia**: which supplementary commemorations to load, if any
//!
//! The pairings are not free. Almost every Orthodox Church keeps the Julian
//! Paschalion; what divides them is the menologion. The "old calendar" churches
//! read the fixed feasts on the Julian calendar too, the "new calendar"
//! churches on the Revised Julian, which agrees with the Gregorian for every
//! date until 2800. So a new-calendar church keeps the Nativity with the West
//! and Pascha with the East, which is not a compromise but exactly what the
//! 1923 congress decided.
//!
//! Only two bodies here use the Gregorian Paschalion: the Finnish Orthodox
//! Church, alone among the Orthodox, and the Byzantine Catholic churches.
use crate ::calendars ::Date ;
use crate ::paschalion ::Paschalion ;
/// Which calendar the *fixed* feasts are read on.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum MenologionKind {
Julian ,
/// Revised Julian, which agrees with the Gregorian for every date until 2800.
RevisedJulian ,
}
2026-09-18 11:28:40 -04:00
/// Greek or Slavic usage. Both keep the same Typikon; they read it a little
/// differently, and the differences are small, real and printed in every
/// calendar that takes a side.
///
/// Two are modelled here:
///
/// - **The Protection of the Theotokos**, 1 October, is a great feast in
/// Slavic usage. Greek practice ranks it lower, and the Church of Greece
/// keeps it on 28 October besides.
/// - **Fish in the Nativity Fast.** Greek practice permits fish on any day but
/// Wednesday and Friday until 17 December; Slavic practice keeps fish to
/// Saturdays and Sundays throughout.
///
/// The split is coarse: a church is assigned the usage its books follow, and
/// no jurisdiction is wholly one thing. Override it with `--tradition`.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum Tradition {
Slavic ,
Greek ,
}
impl Tradition {
pub fn key ( self ) -> & 'static str {
match self {
Tradition ::Slavic => "slavic" ,
Tradition ::Greek => "greek" ,
}
}
pub fn parse ( s : & str ) -> Option < Tradition > {
match s . trim (). to_ascii_lowercase (). as_str () {
"slavic" | "russian" | "slav" => Some ( Tradition ::Slavic ),
"greek" | "byzantine" => Some ( Tradition ::Greek ),
_ => None ,
}
}
}
2026-09-18 11:13:10 -04:00
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum RuleKind {
Orthodox ,
Ruthenian ,
}
/// The short name people use for a paschalion/menologion combination.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum Calendar {
Old ,
New ,
Western ,
}
impl Calendar {
pub fn key ( self ) -> & 'static str {
match self {
Calendar ::Old => "old" ,
Calendar ::New => "new" ,
Calendar ::Western => "western" ,
}
}
}
#[derive(Clone, Copy, Debug)]
pub struct Jurisdiction {
pub key : & 'static str ,
pub name : & 'static str ,
pub paschalion : Paschalion ,
pub menologion : MenologionKind ,
pub rule : RuleKind ,
2026-09-18 11:28:40 -04:00
pub tradition : Tradition ,
2026-09-18 11:13:10 -04:00
/// Supplementary commemoration sets to overlay, fetched not shipped.
pub menaia : & 'static [ & 'static str ],
pub note : & 'static str ,
}
impl Jurisdiction {
pub fn calendar ( & self ) -> Calendar {
match ( self . paschalion , self . menologion ) {
( Paschalion ::Gregorian , MenologionKind ::RevisedJulian ) => Calendar ::Western ,
( _ , MenologionKind ::Julian ) => Calendar ::Old ,
_ => Calendar ::New ,
}
}
/// The ecclesiastical (year, month, day) a civil date is reckoned as.
pub fn fixed_of_civil ( & self , date : Date ) -> ( i32 , u32 , u32 ) {
match self . menologion {
MenologionKind ::Julian => {
let j = date . to_julian ();
( j . year , j . month , j . day )
}
MenologionKind ::RevisedJulian => date . ymd (),
}
}
/// The civil date of an ecclesiastical date in a given church year.
pub fn civil_of_fixed ( & self , year : i32 , month : u32 , day : u32 ) -> Date {
match self . menologion {
MenologionKind ::Julian => {
crate ::calendars ::JulianDate { year , month , day }. to_civil ()
}
MenologionKind ::RevisedJulian => Date ::from_ymd ( year , month , day )
. unwrap_or_else ( || Date ::from_ymd ( year , month , 28 ). expect ( "28th exists" )),
}
}
}
use MenologionKind ::{ Julian as JulMen , RevisedJulian as RevJul };
use Paschalion ::{ Gregorian as GregP , Julian as JulP };
use RuleKind ::{ Orthodox as Orth , Ruthenian as Ruth };
2026-09-18 11:28:40 -04:00
use Tradition ::{ Greek as Gk , Slavic as Sl };
2026-09-18 11:13:10 -04:00
const NO_MENAIA : & [ & str ] = & [];
const RUTHENIAN_MENAIA : & [ & str ] = & [ "ruthenian" ];
/// A reckoning without naming a church. `new` is the default.
pub const CALENDARS : & [ Jurisdiction ] = & [
2026-09-18 11:28:40 -04:00
Jurisdiction { key : "old" , name : "Old Calendar" , paschalion : JulP , menologion : JulMen , rule : Orth , tradition : Sl , menaia : NO_MENAIA ,
2026-09-18 11:13:10 -04:00
note : "Julian throughout, the reckoning of Moscow, Serbia, Georgia, Jerusalem and the Holy Mountain." },
2026-09-18 11:28:40 -04:00
Jurisdiction { key : "new" , name : "New Calendar" , paschalion : JulP , menologion : RevJul , rule : Orth , tradition : Gk , menaia : NO_MENAIA ,
2026-09-18 11:13:10 -04:00
note : "Revised Julian fixed feasts with the Julian Paschalion: Constantinople, Greece, Antioch, Romania, Bulgaria, the OCA." },
2026-09-18 11:28:40 -04:00
Jurisdiction { key : "western" , name : "Gregorian" , paschalion : GregP , menologion : RevJul , rule : Orth , tradition : Gk , menaia : NO_MENAIA ,
2026-09-18 11:13:10 -04:00
note : "Gregorian throughout, Pascha included. Kept by the Finnish Orthodox Church and by most Byzantine Catholics." },
];
pub const JURISDICTIONS : & [ Jurisdiction ] = & [
// old calendar
2026-09-18 11:28:40 -04:00
Jurisdiction { key : "moscow" , name : "Russian Orthodox Church" , paschalion : JulP , menologion : JulMen , rule : Orth , tradition : Sl , menaia : NO_MENAIA , note : "" },
Jurisdiction { key : "rocor" , name : "Russian Orthodox Church Outside Russia" , paschalion : JulP , menologion : JulMen , rule : Orth , tradition : Sl , menaia : NO_MENAIA , note : "" },
Jurisdiction { key : "serbian" , name : "Serbian Orthodox Church" , paschalion : JulP , menologion : JulMen , rule : Orth , tradition : Sl , menaia : NO_MENAIA , note : "" },
Jurisdiction { key : "georgian" , name : "Georgian Orthodox Church" , paschalion : JulP , menologion : JulMen , rule : Orth , tradition : Gk , menaia : NO_MENAIA , note : "" },
Jurisdiction { key : "jerusalem" , name : "Patriarchate of Jerusalem" , paschalion : JulP , menologion : JulMen , rule : Orth , tradition : Gk , menaia : NO_MENAIA , note : "" },
Jurisdiction { key : "athos" , name : "The Holy Mountain" , paschalion : JulP , menologion : JulMen , rule : Orth , tradition : Gk , menaia : NO_MENAIA ,
2026-09-18 11:13:10 -04:00
note : "Athonite practice is stricter than the printed Typikon at many points." },
2026-09-18 11:28:40 -04:00
Jurisdiction { key : "polish" , name : "Polish Orthodox Church" , paschalion : JulP , menologion : JulMen , rule : Orth , tradition : Sl , menaia : NO_MENAIA ,
2026-09-18 11:13:10 -04:00
note : "Returned to the Julian menologion in 2014 after decades on the Revised Julian; some parishes kept the new calendar." },
2026-09-18 11:28:40 -04:00
Jurisdiction { key : "macedonian" , name : "Macedonian Orthodox Church" , paschalion : JulP , menologion : JulMen , rule : Orth , tradition : Sl , menaia : NO_MENAIA , note : "" },
2026-09-18 12:15:05 -04:00
Jurisdiction { key : "acrod" , name : "American Carpatho-Russian Orthodox Diocese" , paschalion : JulP , menologion : JulMen , rule : Orth , tradition : Sl , menaia : NO_MENAIA ,
note : "The Carpatho-Rusyn diocese under Constantinople, formed from the Greek Catholic parishes that returned to Orthodoxy in 1938. The diocese publishes both an old-calendar and a new-calendar cycle and its parishes keep one or the other; this entry is the old one, and `--calendar new --tradition slavic` is the other." },
2026-09-18 11:13:10 -04:00
// new calendar
2026-09-18 11:28:40 -04:00
Jurisdiction { key : "constantinople" , name : "Ecumenical Patriarchate" , paschalion : JulP , menologion : RevJul , rule : Orth , tradition : Gk , menaia : NO_MENAIA , note : "" },
Jurisdiction { key : "goarch" , name : "Greek Orthodox Archdiocese of America" , paschalion : JulP , menologion : RevJul , rule : Orth , tradition : Gk , menaia : NO_MENAIA , note : "" },
Jurisdiction { key : "greece" , name : "Church of Greece" , paschalion : JulP , menologion : RevJul , rule : Orth , tradition : Gk , menaia : NO_MENAIA , note : "" },
Jurisdiction { key : "antiochian" , name : "Antiochian Orthodox Church" , paschalion : JulP , menologion : RevJul , rule : Orth , tradition : Gk , menaia : NO_MENAIA , note : "" },
Jurisdiction { key : "oca" , name : "Orthodox Church in America" , paschalion : JulP , menologion : RevJul , rule : Orth , tradition : Sl , menaia : NO_MENAIA ,
2026-09-18 11:13:10 -04:00
note : "Most parishes keep the new calendar; a minority, chiefly of Carpatho-Russian and Alaskan background, keep the old." },
2026-09-18 11:28:40 -04:00
Jurisdiction { key : "romanian" , name : "Romanian Orthodox Church" , paschalion : JulP , menologion : RevJul , rule : Orth , tradition : Gk , menaia : NO_MENAIA , note : "" },
Jurisdiction { key : "bulgarian" , name : "Bulgarian Orthodox Church" , paschalion : JulP , menologion : RevJul , rule : Orth , tradition : Sl , menaia : NO_MENAIA , note : "" },
Jurisdiction { key : "cyprus" , name : "Church of Cyprus" , paschalion : JulP , menologion : RevJul , rule : Orth , tradition : Gk , menaia : NO_MENAIA , note : "" },
Jurisdiction { key : "albanian" , name : "Orthodox Church of Albania" , paschalion : JulP , menologion : RevJul , rule : Orth , tradition : Gk , menaia : NO_MENAIA , note : "" },
Jurisdiction { key : "ukrainian" , name : "Orthodox Church of Ukraine" , paschalion : JulP , menologion : RevJul , rule : Orth , tradition : Sl , menaia : NO_MENAIA ,
2026-09-18 11:13:10 -04:00
note : "Moved the fixed feasts to the Revised Julian calendar on 1 September 2023. The Julian Paschalion is retained." },
// gregorian throughout
2026-09-18 11:28:40 -04:00
Jurisdiction { key : "finnish" , name : "Finnish Orthodox Church" , paschalion : GregP , menologion : RevJul , rule : Orth , tradition : Gk , menaia : NO_MENAIA ,
2026-09-18 11:13:10 -04:00
note : "The only Orthodox Church keeping the Gregorian Paschalion." },
// eastern catholic
2026-09-18 11:28:40 -04:00
Jurisdiction { key : "ruthenian" , name : "Byzantine Catholic Metropolia of Pittsburgh" , paschalion : GregP , menologion : RevJul , rule : Ruth , tradition : Sl , menaia : RUTHENIAN_MENAIA ,
2026-09-18 11:13:10 -04:00
note : "Gregorian throughout. Fasting is reported under Ruthenian particular law, which binds far less than the Typikon prescribes." },
2026-09-18 11:28:40 -04:00
Jurisdiction { key : "ugcc" , name : "Ukrainian Greek Catholic Church" , paschalion : JulP , menologion : RevJul , rule : Ruth , tradition : Sl , menaia : RUTHENIAN_MENAIA ,
2026-09-18 11:13:10 -04:00
note : "Moved the fixed feasts to the Revised Julian calendar on 1 September 2023, keeping the Julian Paschalion. Eparchies outside Ukraine vary; several keep the Gregorian Paschalion." },
2026-09-18 11:28:40 -04:00
Jurisdiction { key : "melkite" , name : "Melkite Greek Catholic Church" , paschalion : GregP , menologion : RevJul , rule : Ruth , tradition : Gk , menaia : NO_MENAIA ,
2026-09-18 11:13:10 -04:00
note : "Practice is not uniform: parishes in the Middle East commonly keep the Julian Paschalion for the sake of the local Orthodox." },
2026-09-18 11:28:40 -04:00
Jurisdiction { key : "romanian-catholic" , name : "Romanian Greek Catholic Church" , paschalion : GregP , menologion : RevJul , rule : Ruth , tradition : Gk , menaia : NO_MENAIA , note : "" },
2026-09-18 11:13:10 -04:00
];
/// A jurisdiction key, a calendar name, or `None` for the default.
pub fn resolve ( name : Option <& str > ) -> Result <& 'static Jurisdiction , String > {
let Some ( name ) = name else {
return Ok ( & CALENDARS [ 1 ]); // new
};
let key = name . trim (). to_ascii_lowercase ();
JURISDICTIONS
. iter ()
. chain ( CALENDARS . iter ())
. find ( | j | j . key == key )
. ok_or_else ( || name . to_string ())
}