package lectio.cal; import java.io.Serializable; import java.util.Date; import java.util.Map; import java.util.Set; import java.util.SortedMap; import java.util.TreeMap; import org.joda.time.DateTimeConstants; import org.joda.time.LocalDate; /** * Represents a Liturgical year in the Church of Sweden tradition.
* * Note that calendar year and liturgical year doesn't align. The liturgical * year starts first Sunday of Advent the previous calendar year.
* The year used in this class is the year of the Easter Sunday of this liturgical year. * I.e. the liturgical year 2013 starts 2012-12-02.
* * Inspiration from http://www.lysator.liu.se/alma/alma.cgi * * http://www.svenskakyrkan.se/tcrot/kyrkoordningen/filer/KO-kap-28.pdf * * @author marvi */ public class LiturgicalYear implements Serializable { /** * The year this liturgical years Easter Sunday occurs. */ private final int year; private LocalDate easterDay; private int readingCycle; private SortedMap daysOfYear = new TreeMap(); private final String[] swedishCounting = new String[] {"Första", "Andra", "Tredje", "Fjärde", "Femte", "Sjätte", "Sjunde", "Åttonde", "Nionde", "Tionde", "Elfte", "Tolfte", "Trettonde", "Fjortonde", "Femtonde", "Sextonde", "Sjuttonde", "Artonde", "Nittonde", "Tjugonde", "Tjugoförsta", "Tjugoandra", "Tjugotredje", "Tjugofjärde", "Tjugofemte", "Tjugosjätte", "Tjugosjunde"}; /** * * @param year The year to use. */ public LiturgicalYear(int year) { this.year = year; this.readingCycle = this.getReadingCycle(); easterDay = CalculateEaster.forYear(year); populateDaysOfYear(); } /** * Default constructor. Uses current year. */ public LiturgicalYear() { this.year = new LocalDate(new Date()).getYear(); easterDay = CalculateEaster.forYear(year); populateDaysOfYear(); } /** * @return the year */ public int getYear() { return year; } /** * * @return the reading cycle for this liturgical year (1-3) */ public final int getReadingCycle() { return getReadingCycle(year); } public final int getEasterSeries() { return getEasterSeries(year); } public static int getReadingCycle(int year) { if (year < 1986) { return 0; } else if (year < 2003) { return (year - 1986) % 3 + 1; } return (year - 2003) % 3 + 1; } public static int getEasterSeries(int year) { if (year < 2004) { return 0; } return (year - 2002) % 4 + 1; } /** * Maps the holidays to actual dates for this year. */ private void populateDaysOfYear() { // Fixed days daysOfYear.put(new LocalDate(year - 1, 12, 24), new Day("Julnatten", new LocalDate(year - 1, 12, 24), readingCycle)); daysOfYear.put(new LocalDate(year - 1, 12, 25), new Day("Juldagen", new LocalDate(year - 1, 12, 25), readingCycle)); daysOfYear.put(new LocalDate(year - 1, 12, 26), new Day("Annandag jul", new LocalDate(year - 1, 12, 26), readingCycle)); daysOfYear.put(new LocalDate(year - 1, 12, 31), new Day("Nyårsafton", new LocalDate(year - 1, 12, 31), readingCycle)); daysOfYear.put(new LocalDate(year, 1, 1), new Day("Nyårsdagen", new LocalDate(year, 1, 1), readingCycle)); daysOfYear.put(new LocalDate(year, 1, 5), new Day("Trettondagsafton", new LocalDate(year, 1, 5), readingCycle)); daysOfYear.put(new LocalDate(year, 1, 6), new Day("Trettondedag jul", new LocalDate(year, 1, 6), readingCycle)); // Söndagen efter jul infaller inte varje år. LocalDate sej = nextWeekdayOfType(DateTimeConstants.SUNDAY, new LocalDate((year - 1), 12, 26)); if (sej.isBefore(new LocalDate(year, 1, 1))) { daysOfYear.put(sej, new Day("Söndagen efter jul", sej, readingCycle)); } // "Söndagen efter nyår" infaller inte varje år. if (sundayAfterNewYear() != null) { daysOfYear.put(sundayAfterNewYear(), new Day("Söndagen efter nyår", sundayAfterNewYear(), readingCycle)); } // Kyndelsmässodagen (flyttas tillbaka en vecka om den infaller på fastlagssöndagen LocalDate kynd = nextWeekdayOfType(DateTimeConstants.SUNDAY, new LocalDate(year, 2, 1)); if (kynd.equals(easterDay.minusDays(49))) { kynd = kynd.minusDays(7); } daysOfYear.put(kynd, new Day("Kyndelsmässodagen", kynd, readingCycle)); // Söndagar efter trettondedagen int add = 0; int i = 0; while (i < 8) { LocalDate d = firstAfterEpifania().plusDays(add); if (!d.isEqual(kynd) && d.isBefore(easterDay.minusDays(63))) { String prefix = swedishCounting[i]; daysOfYear.put(d, new Day(prefix + " söndagen efter trettondedagen", d, readingCycle)); } else if (d.isEqual(easterDay.minusDays(63)) || d.isAfter(easterDay.minusDays(63))) { i = 8; } add = add + 7; i++; } // Jungfru Marie bebådelsedag LocalDate jmb = nextWeekdayOfType(DateTimeConstants.SUNDAY, new LocalDate(year, 3, 21)); if (jmb.isAfter(easterDay.minusDays(8))) { jmb = easterDay.minusDays(14); } daysOfYear.put(jmb, new Day("Jungfru Marie bebådelsedag", jmb, readingCycle)); //System.out.println(daysOfYear.get(jmb) + " " + easterDay.minusDays(42)); if (!kynd.isEqual(easterDay.minusDays(63))) { daysOfYear.put(easterDay.minusDays(63), new Day("Septuagesima", easterDay.minusDays(63), readingCycle)); } if (!kynd.isEqual(easterDay.minusDays(56))) { daysOfYear.put(easterDay.minusDays(56), new Day("Sexagesima", easterDay.minusDays(56), readingCycle)); } daysOfYear.put(easterDay.minusDays(49), new Day("Fastlagssöndagen", easterDay.minusDays(49), readingCycle)); daysOfYear.put(easterDay.minusDays(46), new Day("Askonsdagen", easterDay.minusDays(46), readingCycle)); if (!jmb.isEqual(easterDay.minusDays(42))) { daysOfYear.put(easterDay.minusDays(42), new Day("Första söndagen i fastan", easterDay.minusDays(42), readingCycle)); } if (!jmb.isEqual(easterDay.minusDays(35))) { daysOfYear.put(easterDay.minusDays(35), new Day("Andra söndagen i fastan", easterDay.minusDays(35), readingCycle)); } if (!jmb.isEqual(easterDay.minusDays(28))) { daysOfYear.put(easterDay.minusDays(28), new Day("Tredje söndagen i fastan", easterDay.minusDays(28), readingCycle)); } if (!jmb.isEqual(easterDay.minusDays(21))) { daysOfYear.put(easterDay.minusDays(21), new Day("Midfastosöndagen", easterDay.minusDays(21), readingCycle)); } if (!jmb.isEqual(easterDay.minusDays(14))) { daysOfYear.put(easterDay.minusDays(14), new Day("Femte söndagen i fastan", easterDay.minusDays(14), readingCycle)); } // Utgår från påsken daysOfYear.put(easterDay, new Day("Påskdagen", easterDay, readingCycle)); daysOfYear.put(easterDay.minusDays(1), new Day("Påsknatten", easterDay.minusDays(1), readingCycle)); daysOfYear.put(easterDay.minusDays(2), new Day("Långfredagen", easterDay.minusDays(2), readingCycle)); daysOfYear.put(easterDay.minusDays(3), new Day("Skärtorsdagen", easterDay.minusDays(3), readingCycle)); daysOfYear.put(easterDay.minusDays(4), new Day("Onsdag i Stilla veckan", easterDay.minusDays(4), readingCycle)); daysOfYear.put(easterDay.minusDays(5), new Day("Tisdag i Stilla veckan", easterDay.minusDays(5), readingCycle)); daysOfYear.put(easterDay.minusDays(6), new Day("Måndag i Stilla veckan", easterDay.minusDays(6), readingCycle)); daysOfYear.put(easterDay.minusDays(7), new Day("Palmsöndagen", easterDay.minusDays(7), readingCycle)); daysOfYear.put(easterDay.plusDays(1), new Day("Annandag påsk", easterDay.plusDays(1), readingCycle)); daysOfYear.put(easterDay.plusDays(7), new Day("Andra söndagen i påsktiden", easterDay.plusDays(7), readingCycle)); daysOfYear.put(easterDay.plusDays(14), new Day("Tredje söndagen i påsktiden", easterDay.plusDays(14), readingCycle)); daysOfYear.put(easterDay.plusDays(21), new Day("Fjärde söndagen i påsktiden", easterDay.plusDays(21), readingCycle)); daysOfYear.put(easterDay.plusDays(28), new Day("Femte söndagen i påsktiden", easterDay.plusDays(28), readingCycle)); daysOfYear.put(easterDay.plusDays(35), new Day("Bönsöndagen", easterDay.plusDays(35), readingCycle)); daysOfYear.put(easterDay.plusDays(39), new Day("Kristi himmelsfärds dag", easterDay.plusDays(39), readingCycle)); daysOfYear.put(easterDay.plusDays(42), new Day("Söndagen före pingst", easterDay.plusDays(42), readingCycle)); daysOfYear.put(easterDay.plusDays(49), new Day("Pingstdagen", easterDay.plusDays(49), readingCycle)); daysOfYear.put(easterDay.plusDays(50), new Day("Annandag pingst", easterDay.plusDays(50), readingCycle)); daysOfYear.put(easterDay.plusDays(56), new Day("Heliga trefaldighets dag", easterDay.plusDays(56), readingCycle)); // Midsommardagen LocalDate msd = nextWeekdayOfType(DateTimeConstants.SATURDAY, new LocalDate(year, 6, 19)); daysOfYear.put(msd, new Day("Midsommardagen", msd, readingCycle)); // Alla helons dag (behövs för att lägga ut trefaldighetstiden) LocalDate ahd = nextWeekdayOfType(DateTimeConstants.SATURDAY, new LocalDate(year, 10, 30)); daysOfYear.put(ahd, new Day("Alla helgons dag", ahd, readingCycle)); daysOfYear.put(ahd.plusDays(1), new Day("Söndagen efter alla helgons dag", ahd.plusDays(1), readingCycle)); // Advent och kyrkoårets slut LocalDate firstAdv = nextWeekdayOfType(DateTimeConstants.SUNDAY, new LocalDate((year - 1), 11, 26)); daysOfYear.put(firstAdv, new Day("Första söndagen i advent", firstAdv, readingCycle)); daysOfYear.put(firstAdv.plusDays(7), new Day("Andra söndagen i advent", firstAdv.plusDays(7), readingCycle)); daysOfYear.put(firstAdv.plusDays(14), new Day("Tredje söndagen i advent", firstAdv.plusDays(14), readingCycle)); daysOfYear.put(firstAdv.plusDays(21), new Day("Fjärde söndagen i advent", firstAdv.plusDays(21), readingCycle)); // Kalenderårsadvent (för att räkna ut Domsöndag LocalDate calFirstAdv = nextWeekdayOfType(DateTimeConstants.SUNDAY, new LocalDate((year), 11, 26)); daysOfYear.put(calFirstAdv.minusDays(7), new Day("Domsöndagen", calFirstAdv.minusDays(7), readingCycle)); daysOfYear.put(calFirstAdv.minusDays(14), new Day("Söndagen före domsöndagen", calFirstAdv.minusDays(7), readingCycle)); // Trefaldighetssöndagarna // Söndagar efter trettondedagen LocalDate firstAfterTre = easterDay.plusDays(63); add = 0; i = 0; while (i < 27) { LocalDate setre = firstAfterTre.plusDays(add); add = add + 7; if (setre.isEqual(ahd.plusDays(1))) { i++; continue; } if (setre.isAfter(calFirstAdv.minusDays(15))) { break; } String etreName = swedishCounting[i]; switch (i) { case 4: daysOfYear.put(setre, new Day("Apostladagen", setre, readingCycle)); break; case 6: daysOfYear.put(setre, new Day("Kristi förklarings dag", setre, readingCycle)); break; default: daysOfYear.put(setre, new Day(etreName + " söndagen efter trefaldighet", setre, readingCycle)); break; } i++; } // Johannes döparens dag daysOfYear.put(msd.plusDays(1), new Day("Den helige Johannes Döparens dag", msd.plusDays(1), readingCycle)); // Den helige Mikaels dag LocalDate hmd = nextWeekdayOfType(DateTimeConstants.SUNDAY, new LocalDate(year, 9, 28)); daysOfYear.put(hmd, new Day("Den helige Mikaels dag", hmd, readingCycle)); // Tacksägelsedagen LocalDate tsd = nextWeekdayOfType(DateTimeConstants.SUNDAY, new LocalDate(year, 9, 30)); tsd = nextWeekdayOfType(DateTimeConstants.SUNDAY, tsd); daysOfYear.put(tsd, new Day("Tacksägelsedagen", tsd, readingCycle)); } private LocalDate sundayAfterNewYear() { LocalDate candidate = nextWeekdayOfType(DateTimeConstants.SUNDAY, new LocalDate(year, 1, 1)); if (candidate.getDayOfMonth() < 6) { return candidate; } return null; } private LocalDate firstAfterEpifania() { LocalDate ep = new LocalDate(year, 1, 6); return nextWeekdayOfType(DateTimeConstants.SUNDAY, ep); } /** * * @param wd The day of week * @param date The date to start from * @return The next date with this weekday */ protected static LocalDate nextWeekdayOfType(int wd, LocalDate date) { if (date.getDayOfWeek() < wd) { date = date.withDayOfWeek(wd); } else { date = date.plusWeeks(1).withDayOfWeek(wd); } return date; } /** * @return a map with a date as key and the Day as value. */ public Map getDaysOfYear() { return daysOfYear; } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("LiturgicalYear{ year="); sb.append(year); sb.append(" "); Set days = daysOfYear.keySet(); for (LocalDate ld : days) { sb.append(daysOfYear.get(ld).toString()); sb.append(" \n "); } sb.append(" }"); return sb.toString(); } }