diff options
Diffstat (limited to 'internal/calendar/calendar.go')
| -rw-r--r-- | internal/calendar/calendar.go | 62 |
1 files changed, 61 insertions, 1 deletions
diff --git a/internal/calendar/calendar.go b/internal/calendar/calendar.go index e0f5217..99a24b3 100644 --- a/internal/calendar/calendar.go +++ b/internal/calendar/calendar.go @@ -29,7 +29,8 @@ func computeEF(date time.Time, sel Selection, layers []Layer) LiturgicalDay { if !ok { continue } - if sameDay(when, date) { + effective := transferIfImpededEF(cel, when) + if sameDay(effective, date) { cands = append(cands, candidate{Cel: cel, Temporal: false, Season: td.Season}) } } @@ -75,6 +76,13 @@ func computeOF(date time.Time, sel Selection, layers []Layer) LiturgicalDay { cands = append(cands, candidate{Cel: cel, Temporal: false, Season: td.Season}) } } + // Movable Marian memorials that have no fixed date (so they cannot live in the + // sanctoral file): Mary, Mother of the Church, and the Immaculate Heart. + for _, mm := range movableMemorialsOF(date.Year()) { + if sameDay(mm.when, date) { + cands = append(cands, candidate{Cel: mm.cel, Temporal: false, Season: td.Season}) + } + } obs, others := pick(cands) day := LiturgicalDay{ @@ -104,6 +112,31 @@ func celebrationDate(cel Celebration, year int, sel Selection) (time.Time, bool) return resolveDate(cel.Date, year, Easter(year)) } +// movableCel is a celebration whose date is computed (relative to Easter), not +// read from a fixed-date layer. +type movableCel struct { + when time.Time + cel Celebration +} + +// movableMemorialsOF returns the Ordinary Form's two movable Marian memorials, +// which have no fixed calendar date: Mary, Mother of the Church (the Monday after +// Pentecost) and the Immaculate Heart of Mary (the Saturday after the Sacred +// Heart, i.e. easter+69). +func movableMemorialsOF(y int) []movableCel { + e := Easter(y) + mk := func(off int, slug, en, pl string) movableCel { + return movableCel{when: e.AddDate(0, 0, off), cel: Celebration{ + Slug: slug, Rank: RankMemorial, Class: ClassBVM, Colour: White, Layer: "universal", + Name: map[string]string{"en": en, "pl": pl}, + }} + } + return []movableCel{ + mk(50, "mary-mother-of-the-church", "Mary, Mother of the Church", "Najświętszej Maryi Panny, Matki Kościoła"), + mk(69, "the-immaculate-heart-of-the-blessed-virgin-mary", "The Immaculate Heart of the Blessed Virgin Mary", "Niepokalanego Serca Najświętszej Maryi Panny"), + } +} + // transferIfImpeded moves a solemnity off a band-1/2 temporal day to the next // free day. Non-solemnities are never transferred (they yield instead). func transferIfImpeded(cel Celebration, when time.Time, sel Selection) time.Time { @@ -126,6 +159,33 @@ func transferIfImpeded(cel Celebration, when time.Time, sel Selection) time.Time return day } +// transferIfImpededEF moves an EF sanctoral feast off a date it cannot be kept +// on. Two rules cover the 1962 cases: All Souls, when Nov 2 is a Sunday, is +// transferred to the Monday (Nov 3); and a I class feast impeded by a I class +// temporal day (Holy Week, the Easter octave) is pushed forward to the next free +// day — for the Annunciation in Holy Week this lands on the Monday after Low +// Sunday, past the whole privileged octave. Lower-rank feasts are only +// commemorated, never transferred. +func transferIfImpededEF(cel Celebration, when time.Time) time.Time { + if when.Month() == time.November && when.Day() == 2 && when.Weekday() == time.Sunday && + strings.Contains(cel.Slug, "all-souls") { + return when.AddDate(0, 0, 1) + } + if cel.Rank != RankClass1 { + return when + } + day := when + for i := 0; i < 30; i++ { + b := temporalEF(day) + if precedenceEF(candidate{Cel: b.Cel, Temporal: true, Season: b.Season}) <= 2 { + day = day.AddDate(0, 0, 1) // impeded by a I class temporal day; push forward + continue + } + return day + } + return day +} + // buildCelebration types a RawCelebration. func buildCelebration(slug string, rc RawCelebration) Celebration { c := Celebration{Slug: strings.TrimSpace(slug), Name: map[string]string{}, Layer: rc.Fields["layer"]} |
