diff options
Diffstat (limited to 'internal/calendar')
| -rw-r--r-- | internal/calendar/calendar.go | 19 | ||||
| -rw-r--r-- | internal/calendar/precedence.go | 21 | ||||
| -rw-r--r-- | internal/calendar/temporal.go | 20 | ||||
| -rw-r--r-- | internal/calendar/temporal_ef.go | 5 |
4 files changed, 62 insertions, 3 deletions
diff --git a/internal/calendar/calendar.go b/internal/calendar/calendar.go index d224e87..9f24caf 100644 --- a/internal/calendar/calendar.go +++ b/internal/calendar/calendar.go @@ -145,10 +145,29 @@ func movableMemorialsOF(y int) []movableCel { // transferIfImpeded moves a solemnity off a band-1/2 temporal day to the next // free day. Non-solemnities are never transferred (they yield instead). +// +// Two impeded solemnities are ANTICIPATED (moved earlier) rather than deferred, +// matching the General Roman Calendar's published transfers: +// - St Joseph (Mar 19) falling in Holy Week goes to the Saturday before Palm +// Sunday. (The Annunciation, by contrast, defers past the octave via the +// generic forward walk below -- to the Monday after the 2nd Sunday of Easter.) +// - The Nativity of St John the Baptist (Jun 24), when the day is a solemnity +// of the Lord (the Sacred Heart or Corpus Christi falling on Jun 24), goes +// to Jun 23. func transferIfImpeded(cel Celebration, when time.Time, sel Selection) time.Time { if cel.Rank != RankSolemnity { return when } + if strings.Contains(cel.Slug, "joseph-husband") { + if palm := Easter(when.Year()).AddDate(0, 0, -7); !when.Before(palm) { + return palm.AddDate(0, 0, -1) // Holy Week -> Saturday before Palm Sunday + } + } + if strings.Contains(cel.Slug, "john-the-baptist") { + if td := temporal(when, sel); td.Cel.Rank == RankSolemnity && td.Class == ClassLord && !td.Sunday { + return when.AddDate(0, 0, -1) // Sacred Heart / Corpus Christi on Jun 24 -> Jun 23 + } + } day := when for i := 0; i < 30; i++ { b := temporal(day, sel) diff --git a/internal/calendar/precedence.go b/internal/calendar/precedence.go index 3b7c0a6..3c7bf5f 100644 --- a/internal/calendar/precedence.go +++ b/internal/calendar/precedence.go @@ -82,6 +82,13 @@ func pick(cands []candidate) (candidate, []candidate) { if pi != pj { return pi < pj } + // Within a band, higher liturgical dignity wins (Table of Liturgical Days: + // of the Lord, then of the BVM, then of saints) -- so a Lord's solemnity + // (Sacred Heart, Corpus Christi) outranks a coinciding saint's solemnity + // rather than losing an alphabetical tie. + if di, dj := dignity(sorted[i].Cel), dignity(sorted[j].Cel); di != dj { + return di < dj + } return sorted[i].Cel.Slug < sorted[j].Cel.Slug }) // General Norms 60: when two obligatory memorials fall on the same day, both @@ -108,6 +115,20 @@ func pick(cands []candidate) (candidate, []candidate) { return sorted[0], sorted[1:] } +// dignity ranks a celebration within its precedence band by the Table of +// Liturgical Days' order of dignity: of the Lord (0), of the BVM (1), of saints +// or unclassified (2). +func dignity(c Celebration) int { + switch c.Class { + case ClassLord: + return 0 + case ClassBVM: + return 1 + default: + return 2 + } +} + // slugIndex returns the position of the candidate with the given slug, or -1. func slugIndex(cands []candidate, slug string) int { for i, c := range cands { diff --git a/internal/calendar/temporal.go b/internal/calendar/temporal.go index b0dc653..1c8d74f 100644 --- a/internal/calendar/temporal.go +++ b/internal/calendar/temporal.go @@ -117,6 +117,15 @@ func ferialDay(season Season, slug string, col Colour, week int, privFeria bool) Cel: Celebration{Slug: slug, Rank: RankFerial, Colour: col, Layer: "temporal"}} } +// privFerialDay builds a band-2 privileged weekday (Ash Wednesday, Holy Week +// Monday-Wednesday): a ferial no sanctoral feast or memorial can displace (only +// a solemnity may, and solemnities transfer off it -- Table of Liturgical Days +// #2). Distinct from ferialDay's PrivFeria (band 9) Lenten/Advent weekdays. +func privFerialDay(season Season, slug string, col Colour, week int) temporalDay { + return temporalDay{Season: season, Colour: col, Week: week, Rank: RankFerial, Privileged: true, + Cel: Celebration{Slug: slug, Rank: RankFerial, Colour: col, Layer: "temporal"}} +} + // temporal computes the temporal identity of date under the given Selection. func temporal(date time.Time, sel Selection) temporalDay { date = date.UTC().Truncate(24 * time.Hour) @@ -180,11 +189,16 @@ func temporal(date time.Time, sel Selection) temporalDay { if sun { return sundayDay(Lent, "palm-sunday", Red, 6) } - return ferialDay(Lent, "holy-week-"+weekdayAbbr(wd), Violet, 6, true) + // Holy Week Mon-Wed are band-2 privileged: no feast/memorial is kept. + return privFerialDay(Lent, "holy-week-"+weekdayAbbr(wd), Violet, 6) case !date.Before(ashWed) && date.Before(palmSunday): // Lent - if !date.Before(ashWed) && date.Before(ashWed.AddDate(0, 0, 4)) { - // Ash Wednesday through the Saturday after (before Lent I). + if sameDay(date, ashWed) { + // Ash Wednesday is band-2 privileged (suppresses any coinciding feast). + return privFerialDay(Lent, "lent-after-ashes-wed", Violet, 0) + } + if date.Before(ashWed.AddDate(0, 0, 4)) { + // Thursday-Saturday after Ash Wednesday (before Lent I): band-9 privileged. return ferialDay(Lent, "lent-after-ashes-"+weekdayAbbr(wd), Violet, 0, true) } lent1 := nextWeekday(ashWed, time.Sunday) diff --git a/internal/calendar/temporal_ef.go b/internal/calendar/temporal_ef.go index 877545c..9e7e7b2 100644 --- a/internal/calendar/temporal_ef.go +++ b/internal/calendar/temporal_ef.go @@ -82,6 +82,11 @@ func temporalEF(date time.Time) temporalDay { easter := Easter(y) season := efSeason(date, y, easter) col := efColour(season) + // The Octave of Pentecost (Whit Monday through the Ember Saturday, easter+50 + // to +55) is red, not the white of the rest of Paschaltide. + if !date.Before(easter.AddDate(0, 0, 50)) && !date.After(easter.AddDate(0, 0, 55)) { + col = Red + } sun := date.Weekday() == time.Sunday // Major feasts of the Lord (I class): nice titles + colour. |
