diff options
| author | Lukasz Kasprzak <lukas@labunix.xyz> | 2026-07-28 08:49:57 +0200 |
|---|---|---|
| committer | Lukasz Kasprzak <lukas@labunix.xyz> | 2026-07-28 08:49:57 +0200 |
| commit | 70b805018f0ae0d8424c3c7de8f1169476385a35 (patch) | |
| tree | 82de4bf52e588ab0c1f31ce0fc68d4b97b3d0de6 /internal/calendar/temporal_ef.go | |
| parent | d3b7f41c7a823bda6b7bafae3a156348c4ce687f (diff) | |
| download | lectio-70b805018f0ae0d8424c3c7de8f1169476385a35.tar.gz lectio-70b805018f0ae0d8424c3c7de8f1169476385a35.zip | |
feat: complete OF+EF calendar coverage (movable feasts, vigils, ember days, transfers)
Ordinary Form:
- Add the movable Marian memorials that have no fixed date: Mary, Mother of the
Church (Monday after Pentecost) and the Immaculate Heart (Saturday after the
Sacred Heart), computed in computeOF.
- General Norms 60: two coinciding obligatory memorials both become optional and
the ferial is observed -- except Mary, Mother of the Church, which keeps
precedence per its 2018 decree.
Extraordinary Form:
- Capture fixed-date vigils in the sanctoral harvest (Christmas, the Nativity of
St John the Baptist, Sts Peter & Paul, St Lawrence, the Assumption, All Saints,
the Immaculate Conception) -- previously filtered out.
- temporalEF: the movable vigils of the Ascension (I class eve) and Pentecost
(Whitsun Eve), and the September/Advent Ember days (II class violet ferias).
- transferIfImpededEF: the Annunciation transfers past Holy Week/the Easter
octave to the Monday after Low Sunday; All Souls moves to Nov 3 when Nov 2 is a
Sunday.
- genlect harvests proper Masses for the new Ember/vigil days.
Adds TestEFCoverage + TestOFMovableMemorials. Bumps to 0.39.0.
Verified per-day: OF 0 real errors vs calapi (2026-2028, 100% correct-observed);
EF 0 real errors vs missalemeum (2025-2027), residual = deep-tail vigil-occurrence
and St Joseph Passiontide-transfer edges (~1-2 days/yr, documented).
Diffstat (limited to 'internal/calendar/temporal_ef.go')
| -rw-r--r-- | internal/calendar/temporal_ef.go | 44 |
1 files changed, 44 insertions, 0 deletions
diff --git a/internal/calendar/temporal_ef.go b/internal/calendar/temporal_ef.go index 2ead3e3..877545c 100644 --- a/internal/calendar/temporal_ef.go +++ b/internal/calendar/temporal_ef.go @@ -114,6 +114,10 @@ func temporalEF(date time.Time) temporalDay { return efCel(TimeAfterPentecost, "ef-sacred-heart", White, RankClass1, 0) case sameDay(date, efChristTheKing(y)): return efCel(TimeAfterPentecost, "ef-christ-the-king", White, RankClass1, 0) + case sameDay(date, easter.AddDate(0, 0, 38)): // Wednesday: Vigil of the Ascension (II class) + return efCel(Easter_, "ef-ascension-vigil", White, RankClass2, 0) + case sameDay(date, easter.AddDate(0, 0, 48)): // Saturday: Vigil of Pentecost / Whitsun Eve (I class) + return efCel(Easter_, "ef-pentecost-vigil", Red, RankClass1, 0) } // Sundays vs ferias of the current season. @@ -146,12 +150,52 @@ func temporalEF(date time.Time) temporalDay { // the temporal office win, matching the 1962 occurrence rules. rank = RankClass1 } + // The Ember Days of September and Advent (Wednesday, Friday, Saturday after + // the third Sunday of the month/season) are II class privileged ferias in + // violet; they displace a III class saint (only commemorated). The Lenten + // Ember days are already III class Lenten ferias, and the Whitsun Ember days + // fall inside the I class Pentecost octave handled above. + if es, ok := efEmberSlug(date, y); ok { + return efCel(season, es, Violet, RankClass2, week) + } // Unique ferial slug (season-week-weekday) so proper ferias (Lent, Advent, // Holy Week, Ember days) can key their own readings; green-season ferias // simply have no lectionary entry and fall back to the Sunday. return efCel(season, "ef-"+string(season)+"-"+strconv.Itoa(week)+"-"+weekdayLower(date), col, rank, week) } +// thirdSundayOfSeptember returns the third Sunday in September of year y. +func thirdSundayOfSeptember(y int) time.Time { + d := time.Date(y, time.September, 1, 0, 0, 0, 0, time.UTC) + for d.Weekday() != time.Sunday { + d = d.AddDate(0, 0, 1) + } + return d.AddDate(0, 0, 14) +} + +// efEmberSlug returns the Ember-day slug for date, if it is an Ember Wednesday, +// Friday or Saturday of September or Advent (the day after the third Sunday + +// 3/5/6). Returns ("", false) otherwise. +func efEmberSlug(date time.Time, y int) (string, bool) { + for _, e := range []struct { + third time.Time + season string + }{ + {thirdSundayOfSeptember(y), "september"}, + {adventStart(y).AddDate(0, 0, 14), "advent"}, // 3rd Sunday of Advent + } { + switch { + case sameDay(date, e.third.AddDate(0, 0, 3)): + return "ef-" + e.season + "-ember-wed", true + case sameDay(date, e.third.AddDate(0, 0, 5)): + return "ef-" + e.season + "-ember-fri", true + case sameDay(date, e.third.AddDate(0, 0, 6)): + return "ef-" + e.season + "-ember-sat", true + } + } + return "", false +} + func weekdayLower(d time.Time) string { return strings.ToLower(d.Weekday().String()) } |
