summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLukasz Kasprzak <lukas@labunix.xyz>2026-08-11 13:26:15 +0200
committerLukasz Kasprzak <lukas@labunix.xyz>2026-08-11 13:26:15 +0200
commitabff8e648d3ee5ac3840e16fbec3e94fce352205 (patch)
tree683ddf5870b1a7ce7dee0299ab506f9ce773315c
parent3c3e84a6ebd4d2a9bcd81410d4a2e5c2fa51005d (diff)
downloadcolitur-abff8e648d3ee5ac3840e16fbec3e94fce352205.tar.gz
colitur-abff8e648d3ee5ac3840e16fbec3e94fce352205.zip
rite(ef): named temporal days, vigils and the Nativity octave
The I-class feasts of the Lord (RG 91 entries 1-3), the Nativity, Ascension and Pentecost vigils (RG 28-34), and the days within the Octave of the Nativity (RG 64-70). Christ the King is the last Sunday of October per the 1960 calendar, not the OF's last Sunday before Advent. Rogation Wednesday coincides with the Ascension vigil; with no precedence framework until Plan 3, temporal emits the higher-ranked vigil.
-rw-r--r--lib/rites/rite_ef/temporal_ef.ml50
-rw-r--r--lib/rites/rite_ef/temporal_ef.mli8
-rw-r--r--test/test_temporal_ef.ml43
3 files changed, 98 insertions, 3 deletions
diff --git a/lib/rites/rite_ef/temporal_ef.ml b/lib/rites/rite_ef/temporal_ef.ml
index c975316..9560940 100644
--- a/lib/rites/rite_ef/temporal_ef.ml
+++ b/lib/rites/rite_ef/temporal_ef.ml
@@ -46,3 +46,53 @@ let season d =
else if before d easter then Passiontide (* RG 75; Holy Saturday included *)
else if Date.compare d paschal_end <= 0 then Paschaltide (* RG 76 *)
else Time_after_pentecost (* RG 77 *)
+
+(* Last Sunday of October, per the 1960 calendar -- NOT the OF's last Sunday
+ before Advent. Register ยง6 flags this for primary-source confirmation. *)
+let christ_the_king y = sunday_on_or_before (mk y 10 31)
+
+let same a b = Date.compare a b = 0
+
+(* Named temporal days: the I-class feasts of the Lord (RG 91 entries 1-3), the
+ vigils (RG 28-34, RG 91 entries 5 and 9) and the days within the Octave of
+ the Nativity (RG 64-70, RG 91 entry 17).
+
+ Returns (season, slug, colour, rank, week). *)
+let named d =
+ let y = Date.year d in
+ let easter = Computus.gregorian_easter y in
+ let off n = Date.add_days easter n in
+ let m = Date.month d and dd = Date.day d in
+ if m = 12 && dd = 25 then Some (Christmastide, "ef-nativity", Colour.White, Class1, None)
+ else if m = 12 && dd = 24 then
+ (* RG 91 entry 5: the Vigil of the Nativity is I class. lectio has no slug
+ for it, so this key has no lectionary entry until Plan 3 fills it. *)
+ Some (Advent, "ef-nativity-vigil", Colour.Violet, Class1, None)
+ else if m = 12 && (dd = 29 || dd = 30 || dd = 31) then
+ (* Days within the Octave of the Nativity; 26-28 Dec are Stephen, John and
+ the Innocents, hence sanctoral (Plan 3). Colitur slugs -- lectionary gap. *)
+ Some (Christmastide, Printf.sprintf "ef-nativity-octave-day-%d" (dd - 24), Colour.White, Class2, None)
+ else if m = 1 && dd = 1 then Some (Christmastide, "ef-circumcision", Colour.White, Class1, None)
+ else if m = 1 && dd = 6 then Some (Christmastide, "ef-epiphany", Colour.White, Class1, None)
+ else if same d (off (-46)) then Some (Lent, "ef-ash-wednesday", Colour.Violet, Class1, None)
+ else if same d (off (-14)) then Some (Passiontide, "ef-passion-sunday", Colour.Violet, Class1, Some 1)
+ else if same d (off (-7)) then Some (Passiontide, "ef-palm-sunday", Colour.Violet, Class1, Some 2)
+ else if same d easter then Some (Paschaltide, "ef-easter-sunday", Colour.White, Class1, Some 1)
+ else if same d (off 7) then Some (Paschaltide, "ef-low-sunday", Colour.White, Class1, Some 2)
+ else if same d (off 38) then
+ (* RG 91 entry 21: II-class vigil. It is also Rogation Wednesday; with no
+ precedence framework until Plan 3, temporal emits the higher-ranked
+ vigil and the Rogation commemoration waits for RG 108-111. *)
+ Some (Paschaltide, "ef-ascension-vigil", Colour.White, Class2, None)
+ else if same d (off 39) then Some (Paschaltide, "ef-ascension", Colour.White, Class1, None)
+ else if same d (off 48) then
+ Some (Paschaltide, "ef-pentecost-vigil", Colour.Red, Class1, None) (* RG 91 entry 9 *)
+ else if same d (off 49) then Some (Paschaltide, "ef-pentecost", Colour.Red, Class1, None)
+ else if same d (off 56) then Some (Time_after_pentecost, "ef-trinity", Colour.White, Class1, Some 1)
+ else if same d (off 60) then
+ Some (Time_after_pentecost, "ef-corpus-christi", Colour.White, Class1, None)
+ else if same d (off 68) then
+ Some (Time_after_pentecost, "ef-sacred-heart", Colour.White, Class1, None)
+ else if same d (christ_the_king y) then
+ Some (Time_after_pentecost, "ef-christ-the-king", Colour.White, Class1, None)
+ else None
diff --git a/lib/rites/rite_ef/temporal_ef.mli b/lib/rites/rite_ef/temporal_ef.mli
index 7ee75e5..0a9656a 100644
--- a/lib/rites/rite_ef/temporal_ef.mli
+++ b/lib/rites/rite_ef/temporal_ef.mli
@@ -10,3 +10,11 @@ val advent_start : int -> Date.t
val year_start : int -> Date.t
val season : Date.t -> Vocab_ef.season
+
+(** Last Sunday of October, per the 1960 calendar. *)
+val christ_the_king : int -> Date.t
+
+(** The named temporal days: I-class feasts of the Lord, vigils, and days within
+ the Octave of the Nativity. Returns (season, slug, colour, rank, week). *)
+val named :
+ Date.t -> (Vocab_ef.season * string * Colour.t * Vocab_ef.rank * int option) option
diff --git a/test/test_temporal_ef.ml b/test/test_temporal_ef.ml
index eb672d9..1353c43 100644
--- a/test/test_temporal_ef.ml
+++ b/test/test_temporal_ef.ml
@@ -54,12 +54,49 @@ let test_seasons () =
Alcotest.(check string) "Sat after Pentecost 30 May 2026" "paschaltide" (season_str (d 2026 5 30));
Alcotest.(check string) "Trinity 31 May 2026" "time-after-pentecost" (season_str (d 2026 5 31))
-let suite_extra_seasons =
+let named_slug dt = match T.named dt with
+ | Some (_, slug, _, _, _) -> slug
+ | None -> "<none>"
+
+let test_named_feasts () =
+ (* Easter 2026 = 5 April. *)
+ Alcotest.(check string) "nativity" "ef-nativity" (named_slug (d 2026 12 25));
+ Alcotest.(check string) "nativity vigil" "ef-nativity-vigil" (named_slug (d 2026 12 24));
+ Alcotest.(check string) "circumcision" "ef-circumcision" (named_slug (d 2026 1 1));
+ Alcotest.(check string) "epiphany" "ef-epiphany" (named_slug (d 2026 1 6));
+ Alcotest.(check string) "ash wednesday" "ef-ash-wednesday" (named_slug (d 2026 2 18));
+ Alcotest.(check string) "passion sunday" "ef-passion-sunday" (named_slug (d 2026 3 22));
+ Alcotest.(check string) "palm sunday" "ef-palm-sunday" (named_slug (d 2026 3 29));
+ Alcotest.(check string) "easter" "ef-easter-sunday" (named_slug (d 2026 4 5));
+ Alcotest.(check string) "low sunday" "ef-low-sunday" (named_slug (d 2026 4 12));
+ Alcotest.(check string) "ascension vigil" "ef-ascension-vigil" (named_slug (d 2026 5 13));
+ Alcotest.(check string) "ascension" "ef-ascension" (named_slug (d 2026 5 14));
+ Alcotest.(check string) "pentecost vigil" "ef-pentecost-vigil" (named_slug (d 2026 5 23));
+ Alcotest.(check string) "pentecost" "ef-pentecost" (named_slug (d 2026 5 24));
+ Alcotest.(check string) "trinity" "ef-trinity" (named_slug (d 2026 5 31));
+ Alcotest.(check string) "corpus christi" "ef-corpus-christi" (named_slug (d 2026 6 4));
+ Alcotest.(check string) "sacred heart" "ef-sacred-heart" (named_slug (d 2026 6 12));
+ Alcotest.(check string) "an ordinary day is not named" "<none>" (named_slug (d 2026 7 15))
+
+let test_christ_the_king () =
+ (* 1960 calendar: the LAST Sunday of October, not the OF's last before Advent. *)
+ Alcotest.(check string) "2026" "2026-10-25" (D.to_iso8601 (T.christ_the_king 2026));
+ Alcotest.(check bool) "always a Sunday" true (D.weekday (T.christ_the_king 2026) = D.Sun);
+ Alcotest.(check string) "slug" "ef-christ-the-king" (named_slug (T.christ_the_king 2026))
+
+let test_nativity_octave () =
+ Alcotest.(check string) "29 Dec" "ef-nativity-octave-day-5" (named_slug (d 2026 12 29));
+ Alcotest.(check string) "31 Dec" "ef-nativity-octave-day-7" (named_slug (d 2026 12 31))
+
+let suite_extra =
[ Alcotest.test_case "advent start" `Quick test_advent_start;
- Alcotest.test_case "seasons" `Quick test_seasons ]
+ Alcotest.test_case "seasons" `Quick test_seasons;
+ Alcotest.test_case "named feasts" `Quick test_named_feasts;
+ Alcotest.test_case "christ the king" `Quick test_christ_the_king;
+ Alcotest.test_case "nativity octave" `Quick test_nativity_octave ]
let suite =
( "Rite_ef",
[ Alcotest.test_case "vocab roundtrips" `Quick test_vocab_roundtrips;
Alcotest.test_case "slug words" `Quick test_slug_words ]
- @ suite_extra_seasons )
+ @ suite_extra )