/** * Copyright (C) 2014 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.strata.basics.date; import static java.time.DayOfWeek.FRIDAY; import static java.time.DayOfWeek.MONDAY; import static java.time.DayOfWeek.SATURDAY; import static java.time.DayOfWeek.SUNDAY; import static java.time.DayOfWeek.THURSDAY; import static java.time.DayOfWeek.TUESDAY; import static java.time.DayOfWeek.WEDNESDAY; import static java.time.temporal.TemporalAdjusters.dayOfWeekInMonth; import static java.time.temporal.TemporalAdjusters.firstInMonth; import static java.time.temporal.TemporalAdjusters.lastInMonth; import static java.time.temporal.TemporalAdjusters.nextOrSame; import static java.util.stream.Collectors.toSet; import java.time.DayOfWeek; import java.time.LocalDate; import java.time.MonthDay; import java.time.temporal.TemporalAdjusters; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; /** * Implementation of some common global holiday calendars. * <p> * The data provided here has been identified through direct research and is not * derived from a vendor of holiday calendar data. * This data may or may not be sufficient for your production needs. */ final class GlobalHolidayCalendars { /** * The holiday calendar for London, United Kingdom, with code 'GBLO'. * <p> * This constant provides the calendar for London bank holidays. * <p> * The default implementation is based on original research and covers 1950 to 2099. * Future dates are an extrapolations of the latest known rules. */ public static final HolidayCalendar GBLO = generateLondon(); /** * The holiday calendar for Paris, France, with code 'FRPA'. * <p> * This constant provides the calendar for Paris public holidays. * <p> * The default implementation is based on original research and covers 1950 to 2099. * Future and past dates are an extrapolations of the latest known rules. */ public static final HolidayCalendar FRPA = generateParis(); /** * The holiday calendar for Zurich, Switzerland, with code 'EUTA'. * <p> * This constant provides the calendar for Zurich public holidays. * <p> * The default implementation is based on original research and covers 1950 to 2099. * Future and past dates are an extrapolations of the latest known rules. */ public static final HolidayCalendar CHZU = generateZurich(); /** * The holiday calendar for the European Union TARGET system, with code 'EUTA'. * <p> * This constant provides the calendar for the TARGET interbank payment system holidays. * <p> * The default implementation is based on original research and covers 1997 to 2099. * Future dates are an extrapolations of the latest known rules. * <p> * Referenced by the 2006 ISDA definitions 1.8. */ public static final HolidayCalendar EUTA = generateEuropeanTarget(); /** * The holiday calendar for United States Government Securities, with code 'USGS'. * <p> * This constant provides the calendar for United States Government Securities as per SIFMA. * <p> * The default implementation is based on original research and covers 1950 to 2099. * Future and past dates are an extrapolations of the latest known rules. * <p> * Referenced by the 2006 ISDA definitions 1.11. */ public static final HolidayCalendar USGS = generateUsGovtSecurities(); /** * The holiday calendar for New York, United States, with code 'USNY'. * <p> * This constant provides the calendar for New York holidays. * <p> * The default implementation is based on original research and covers 1950 to 2099. * Future and past dates are an extrapolations of the latest known rules. */ public static final HolidayCalendar USNY = generateUsNewYork(); /** * The holiday calendar for the Federal Reserve Bank of New York, with code 'NYFD'. * <p> * This constant provides the calendar for the Federal Reserve Bank of New York holidays. * <p> * The default implementation is based on original research and covers 1950 to 2099. * Future and past dates are an extrapolations of the latest known rules. * <p> * Referenced by the 2006 ISDA definitions 1.9. */ public static final HolidayCalendar NYFD = generateNewYorkFed(); /** * The holiday calendar for the New York Stock Exchange, with code 'NYSE'. * <p> * This constant provides the calendar for the New York Stock Exchange. * <p> * The default implementation is based on original research and covers 1950 to 2099. * Future and past dates are an extrapolations of the latest known rules. * <p> * Referenced by the 2006 ISDA definitions 1.10. */ public static final HolidayCalendar NYSE = generateNewYorkStockExchange(); /** * The holiday calendar for Tokyo, Japan, with code 'JPTO'. * <p> * This constant provides the calendar for Tokyo bank holidays. * <p> * The default implementation is based on original research and covers 1950 to 2099. * Future and past dates are an extrapolations of the latest known rules. */ public static final HolidayCalendar JPTO = generateTokyo(); /** * The holiday calendar for Sydney, Australia, with code 'AUSY'. * <p> * This constant provides the calendar for Sydney holidays. * <p> * The default implementation is based on original research and covers 1950 to 2099. * Future and past dates are an extrapolations of the latest known rules. */ public static final HolidayCalendar AUSY = generateSydney(); /** * The holiday calendar for Brazil with code 'BRBD'. * <p> * This constant references the combined calendar for Brazil bank holidays. * This unites city-level calendars. * <p> * The default implementation is based on original research and covers 1950 to 2099. * Future and past dates are an extrapolations of the latest known rules. */ public static final HolidayCalendar BRBD = generateBrazil(); /** * The holiday calendar for Toronto, Canada, with code 'CATO'. * <p> * This constant provides the calendar for Toronto holidays. * <p> * The default implementation is based on original research and covers 1950 to 2099. * Future and past dates are an extrapolations of the latest known rules. */ public static final HolidayCalendar CATO = generateToronto(); /** * The holiday calendar of Prague, Czech Republic, with code 'CZPR'. * <p> * This constant provides the calendar for Prague bank holidays. * <p> * The default implementation is based on original research and covers 1950 to 2099. * Future and past dates are an extrapolations of the latest known rules. */ public static final HolidayCalendar CZPR = generatePrague(); /** * The holiday calendar for Copenhagen, Denmark, with code 'DKCO'. * <p> * This constant provides the calendar for Copenhagen holidays. * <p> * The default implementation is based on original research and covers 1950 to 2099. * Future and past dates are an extrapolations of the latest known rules. */ public static final HolidayCalendar DKCO = generateCopenhagen(); /** * The holiday calendar for Budapest, Hungary, with code 'HUBU'. * <p> * This constant provides the calendar for Budapest holidays. * <p> * The default implementation is based on original research and covers 1950 to 2099. * Future and past dates are an extrapolations of the latest known rules. */ public static final HolidayCalendar HUBU = generateBudapest(); /** * The holiday calendar for Mexico City, Mexico, with code 'HUBU'. * <p> * This constant provides the calendar for Mexico City holidays. * <p> * The default implementation is based on original research and covers 1950 to 2099. * Future and past dates are an extrapolations of the latest known rules. */ public static final HolidayCalendar MXMC = generateMexicoCity(); /** * The holiday calendar for Oslo, Norway, with code 'NOOS'. * <p> * This constant provides the calendar for Oslo holidays. * <p> * The default implementation is based on original research and covers 1950 to 2099. * Future and past dates are an extrapolations of the latest known rules. */ public static final HolidayCalendar NOOS = generateOslo(); /** * The holiday calendar for Warsaw, Poland, with code 'PLWA'. * <p> * This constant provides the calendar for Warsaw holidays. * <p> * The default implementation is based on original research and covers 1950 to 2099. * Future and past dates are an extrapolations of the latest known rules. */ public static final HolidayCalendar PLWA = generateWarsaw(); /** * The holiday calendar for Stockholm, Sweden, with code 'SEST'. * <p> * This constant provides the calendar for Stockholm holidays. * <p> * The default implementation is based on original research and covers 1950 to 2099. * Future and past dates are an extrapolations of the latest known rules. */ public static final HolidayCalendar SEST = generateStockholm(); /** * The holiday calendar for Johannesburg, South Africa, with code 'ZAJO'. * <p> * This constant provides the calendar for Johannesburg holidays. * <p> * The default implementation is based on original research and covers 1950 to 2099. * Future and past dates are an extrapolations of the latest known rules. */ public static final HolidayCalendar ZAJO = generateJohannesburg(); //------------------------------------------------------------------------- /** * Restricted constructor. */ private GlobalHolidayCalendars() { } //------------------------------------------------------------------------- // generate GBLO // common law (including before 1871) good friday and christmas day (unadjusted for weekends) // from 1871 easter monday, whit monday, first Mon in Aug and boxing day // from 1965 to 1970, first in Aug moved to Mon after last Sat in Aug // from 1971, whitsun moved to last Mon in May, last Mon in Aug // from 1974, added new year // from 1978, added first Mon in May // see Hansard for specific details // 1965, Whitsun, Last Mon Aug - http://hansard.millbanksystems.com/commons/1964/mar/04/staggered-holidays // 1966, Whitsun May - http://hansard.millbanksystems.com/commons/1964/mar/04/staggered-holidays // 1966, 29th Aug - http://hansard.millbanksystems.com/written_answers/1965/nov/25/august-bank-holiday // 1967, 29th May, 28th Aug - http://hansard.millbanksystems.com/written_answers/1965/jun/03/bank-holidays-1967-and-1968 // 1968, 3rd Jun, 2nd Sep - http://hansard.millbanksystems.com/written_answers/1965/jun/03/bank-holidays-1967-and-1968 // 1969, 26th May, 1st Sep - http://hansard.millbanksystems.com/written_answers/1967/mar/21/bank-holidays-1969-dates // 1970, 25th May, 31st Aug - http://hansard.millbanksystems.com/written_answers/1967/jul/28/bank-holidays static ImmutableHolidayCalendar generateLondon() { List<LocalDate> holidays = new ArrayList<>(2000); for (int year = 1950; year <= 2099; year++) { // new year if (year >= 1974) { holidays.add(bumpToMon(first(year, 1))); } // easter holidays.add(easter(year).minusDays(2)); holidays.add(easter(year).plusDays(1)); // early May if (year == 1995) { // ve day holidays.add(date(1995, 5, 8)); } else if (year >= 1978) { holidays.add(first(year, 5).with(firstInMonth(MONDAY))); } // spring if (year == 2002) { // golden jubilee holidays.add(date(2002, 6, 3)); holidays.add(date(2002, 6, 4)); } else if (year == 2012) { // diamond jubilee holidays.add(date(2012, 6, 4)); holidays.add(date(2012, 6, 5)); } else if (year == 1967 || year == 1970) { holidays.add(first(year, 5).with(lastInMonth(MONDAY))); } else if (year < 1971) { // whitsun holidays.add(easter(year).plusDays(50)); } else { holidays.add(first(year, 5).with(lastInMonth(MONDAY))); } // summer if (year < 1965) { holidays.add(first(year, 8).with(firstInMonth(MONDAY))); } else if (year < 1971) { holidays.add(first(year, 8).with(lastInMonth(SATURDAY)).plusDays(2)); } else { holidays.add(first(year, 8).with(lastInMonth(MONDAY))); } // christmas holidays.add(christmasBumpedSatSun(year)); holidays.add(boxingDayBumpedSatSun(year)); } holidays.add(date(2011, 4, 29)); // royal wedding holidays.add(date(1999, 12, 31)); // millennium removeSatSun(holidays); return ImmutableHolidayCalendar.of(HolidayCalendarIds.GBLO, holidays, SATURDAY, SUNDAY); } //------------------------------------------------------------------------- // generate FRPA // data sources // http://www.legifrance.gouv.fr/affichCodeArticle.do?idArticle=LEGIARTI000006902611&cidTexte=LEGITEXT000006072050 // http://jollyday.sourceforge.net/data/fr.html // Euronext holidays only New Year, Good Friday, Easter Monday, Labour Day, Christmas Day, Boxing Day // New Years Eve is holiday for cash markets and derivatives in 2015 // https://www.euronext.com/en/holidays-and-hours // https://www.euronext.com/en/trading/nyse-euronext-trading-calendar/archives // evidence suggests that Monday is holiday when Tuesday is, and Friday is holiday when Thursday is static ImmutableHolidayCalendar generateParis() { List<LocalDate> holidays = new ArrayList<>(2000); for (int year = 1950; year <= 2099; year++) { holidays.add(date(year, 1, 1)); // new year holidays.add(easter(year).minusDays(2)); // good friday holidays.add(easter(year).plusDays(1)); // easter monday holidays.add(date(year, 5, 1)); // labour day holidays.add(date(year, 5, 8)); // victory in europe holidays.add(easter(year).plusDays(39)); // ascension day if (year <= 2004 || year >= 2008) { holidays.add(easter(year).plusDays(50)); // whit monday } holidays.add(date(year, 7, 14)); // bastille holidays.add(date(year, 8, 15)); // assumption of mary holidays.add(date(year, 11, 1)); // all saints holidays.add(date(year, 11, 11)); // armistice day holidays.add(date(year, 12, 25)); // christmas day holidays.add(date(year, 12, 26)); // saint stephen } holidays.add(date(1999, 12, 31)); // millennium applyBridging(holidays); removeSatSun(holidays); return ImmutableHolidayCalendar.of(HolidayCalendarIds.FRPA, holidays, SATURDAY, SUNDAY); } //------------------------------------------------------------------------- // generate CHZU // data sources // http://jollyday.sourceforge.net/data/ch.html // https://github.com/lballabio/quantlib/blob/master/QuantLib/ql/time/calendars/switzerland.cpp // http://www.six-swiss-exchange.com/funds/trading/trading_and_settlement_calendar_en.html // http://www.six-swiss-exchange.com/swx_messages/online/swx7299e.pdf static ImmutableHolidayCalendar generateZurich() { List<LocalDate> holidays = new ArrayList<>(2000); for (int year = 1950; year <= 2099; year++) { holidays.add(date(year, 1, 1)); // new year holidays.add(date(year, 1, 2)); // saint berchtoldstag holidays.add(easter(year).minusDays(2)); // good friday holidays.add(easter(year).plusDays(1)); // easter monday holidays.add(date(year, 5, 1)); // labour day holidays.add(easter(year).plusDays(39)); // ascension day holidays.add(easter(year).plusDays(50)); // whit monday holidays.add(date(year, 8, 1)); // national day holidays.add(date(year, 12, 25)); // christmas day holidays.add(date(year, 12, 26)); // saint stephen } holidays.add(date(1999, 12, 31)); // millennium holidays.add(date(2000, 1, 3)); // millennium removeSatSun(holidays); return ImmutableHolidayCalendar.of(HolidayCalendarIds.CHZU, holidays, SATURDAY, SUNDAY); } //------------------------------------------------------------------------- // generate EUTA // 1997 - 1998 (testing phase), Jan 1, christmas day // https://www.ecb.europa.eu/pub/pdf/other/tagien.pdf // in 1999, Jan 1, christmas day, Dec 26, Dec 31 // http://www.ecb.europa.eu/press/pr/date/1999/html/pr990715_1.en.html // http://www.ecb.europa.eu/press/pr/date/1999/html/pr990331.en.html // in 2000, Jan 1, good friday, easter monday, May 1, christmas day, Dec 26 // http://www.ecb.europa.eu/press/pr/date/1999/html/pr990715_1.en.html // in 2001, Jan 1, good friday, easter monday, May 1, christmas day, Dec 26, Dec 31 // http://www.ecb.europa.eu/press/pr/date/2000/html/pr000525_2.en.html // from 2002, Jan 1, good friday, easter monday, May 1, christmas day, Dec 26 // http://www.ecb.europa.eu/press/pr/date/2000/html/pr001214_4.en.html static ImmutableHolidayCalendar generateEuropeanTarget() { List<LocalDate> holidays = new ArrayList<>(2000); for (int year = 1997; year <= 2099; year++) { if (year >= 2000) { holidays.add(date(year, 1, 1)); holidays.add(easter(year).minusDays(2)); holidays.add(easter(year).plusDays(1)); holidays.add(date(year, 5, 1)); holidays.add(date(year, 12, 25)); holidays.add(date(year, 12, 26)); } else { // 1997 to 1999 holidays.add(date(year, 1, 1)); holidays.add(date(year, 12, 25)); } if (year == 1999 || year == 2001) { holidays.add(date(year, 12, 31)); } } removeSatSun(holidays); return ImmutableHolidayCalendar.of(HolidayCalendarIds.EUTA, holidays, SATURDAY, SUNDAY); } //------------------------------------------------------------------------- // common US holidays private static void usCommon( List<LocalDate> holidays, int year, boolean bumpBack, boolean columbusVeteran, int mlkStartYear) { // new year, adjusted if Sunday holidays.add(bumpSunToMon(date(year, 1, 1))); // martin luther king if (year >= mlkStartYear) { holidays.add(date(year, 1, 1).with(dayOfWeekInMonth(3, MONDAY))); } // washington if (year < 1971) { holidays.add(bumpSunToMon(date(year, 2, 22))); } else { holidays.add(date(year, 2, 1).with(dayOfWeekInMonth(3, MONDAY))); } // memorial if (year < 1971) { holidays.add(bumpSunToMon(date(year, 5, 30))); } else { holidays.add(date(year, 5, 1).with(lastInMonth(MONDAY))); } // labor day holidays.add(date(year, 9, 1).with(firstInMonth(MONDAY))); // columbus day if (columbusVeteran) { if (year < 1971) { holidays.add(bumpSunToMon(date(year, 10, 12))); } else { holidays.add(date(year, 10, 1).with(dayOfWeekInMonth(2, MONDAY))); } } // veterans day if (columbusVeteran) { if (year >= 1971 && year < 1978) { holidays.add(date(year, 10, 1).with(dayOfWeekInMonth(4, MONDAY))); } else { holidays.add(bumpSunToMon(date(year, 11, 11))); } } // thanksgiving holidays.add(date(year, 11, 1).with(dayOfWeekInMonth(4, THURSDAY))); // independence day & christmas day if (bumpBack) { holidays.add(bumpToFriOrMon(date(year, 7, 4))); holidays.add(bumpToFriOrMon(date(year, 12, 25))); } else { holidays.add(bumpSunToMon(date(year, 7, 4))); holidays.add(bumpSunToMon(date(year, 12, 25))); } } // generate USGS // http://www.sifma.org/services/holiday-schedule/ static ImmutableHolidayCalendar generateUsGovtSecurities() { List<LocalDate> holidays = new ArrayList<>(2000); for (int year = 1950; year <= 2099; year++) { usCommon(holidays, year, true, true, 1986); // good friday, in 1999/2007 only a partial holiday holidays.add(easter(year).minusDays(2)); // hurricane sandy if (year == 2012) { holidays.add(date(year, 10, 30)); } } removeSatSun(holidays); return ImmutableHolidayCalendar.of(HolidayCalendarIds.USGS, holidays, SATURDAY, SUNDAY); } //------------------------------------------------------------------------- // generate USNY // http://www.cs.ny.gov/attendance_leave/2012_legal_holidays.cfm // http://www.cs.ny.gov/attendance_leave/2013_legal_holidays.cfm // etc // ignore election day and lincoln day static ImmutableHolidayCalendar generateUsNewYork() { List<LocalDate> holidays = new ArrayList<>(2000); for (int year = 1950; year <= 2099; year++) { usCommon(holidays, year, false, true, 1986); } removeSatSun(holidays); return ImmutableHolidayCalendar.of(HolidayCalendarIds.USNY, holidays, SATURDAY, SUNDAY); } //------------------------------------------------------------------------- // generate NYFD // http://www.ny.frb.org/aboutthefed/holiday_schedule.html static ImmutableHolidayCalendar generateNewYorkFed() { List<LocalDate> holidays = new ArrayList<>(2000); for (int year = 1950; year <= 2099; year++) { usCommon(holidays, year, false, true, 1986); } removeSatSun(holidays); return ImmutableHolidayCalendar.of(HolidayCalendarIds.NYFD, holidays, SATURDAY, SUNDAY); } //------------------------------------------------------------------------- // generate NYSE // https://www.nyse.com/markets/hours-calendars // http://www1.nyse.com/pdfs/closings.pdf static ImmutableHolidayCalendar generateNewYorkStockExchange() { List<LocalDate> holidays = new ArrayList<>(2000); for (int year = 1950; year <= 2099; year++) { usCommon(holidays, year, true, false, 1998); // good friday holidays.add(easter(year).minusDays(2)); } // Lincoln day 1896-1953 // Columbus day 1909-1953 // Veterans day 1934-1953 for (int i = 1950; i <= 1953; i++) { holidays.add(date(i, 2, 12)); holidays.add(date(i, 10, 12)); holidays.add(date(i, 11, 11)); } // election day, Tue after first Monday of November for (int i = 1950; i <= 1968; i++) { holidays.add(date(i, 11, 1).with(TemporalAdjusters.nextOrSame(MONDAY)).plusDays(1)); } holidays.add(date(1972, 11, 7)); holidays.add(date(1976, 11, 2)); holidays.add(date(1980, 11, 4)); // special days holidays.add(date(1955, 12, 24)); // Christmas Eve holidays.add(date(1956, 12, 24)); // Christmas Eve holidays.add(date(1958, 12, 26)); // Day after Christmas holidays.add(date(1961, 5, 29)); // Decoration day holidays.add(date(1963, 11, 25)); // Death of John F Kennedy holidays.add(date(1965, 12, 24)); // Christmas Eve holidays.add(date(1968, 2, 12)); // Lincoln birthday holidays.add(date(1968, 4, 9)); // Death of Martin Luther King holidays.add(date(1968, 6, 12)); // Paperwork crisis holidays.add(date(1968, 6, 19)); // Paperwork crisis holidays.add(date(1968, 6, 26)); // Paperwork crisis holidays.add(date(1968, 7, 3)); // Paperwork crisis holidays.add(date(1968, 7, 5)); // Day after independence holidays.add(date(1968, 7, 10)); // Paperwork crisis holidays.add(date(1968, 7, 17)); // Paperwork crisis holidays.add(date(1968, 7, 24)); // Paperwork crisis holidays.add(date(1968, 7, 31)); // Paperwork crisis holidays.add(date(1968, 8, 7)); // Paperwork crisis holidays.add(date(1968, 8, 13)); // Paperwork crisis holidays.add(date(1968, 8, 21)); // Paperwork crisis holidays.add(date(1968, 8, 28)); // Paperwork crisis holidays.add(date(1968, 9, 4)); // Paperwork crisis holidays.add(date(1968, 9, 11)); // Paperwork crisis holidays.add(date(1968, 9, 18)); // Paperwork crisis holidays.add(date(1968, 9, 25)); // Paperwork crisis holidays.add(date(1968, 10, 2)); // Paperwork crisis holidays.add(date(1968, 10, 9)); // Paperwork crisis holidays.add(date(1968, 10, 16)); // Paperwork crisis holidays.add(date(1968, 10, 23)); // Paperwork crisis holidays.add(date(1968, 10, 30)); // Paperwork crisis holidays.add(date(1968, 11, 6)); // Paperwork crisis holidays.add(date(1968, 11, 13)); // Paperwork crisis holidays.add(date(1968, 11, 20)); // Paperwork crisis holidays.add(date(1968, 11, 27)); // Paperwork crisis holidays.add(date(1968, 12, 4)); // Paperwork crisis holidays.add(date(1968, 12, 11)); // Paperwork crisis holidays.add(date(1968, 12, 18)); // Paperwork crisis holidays.add(date(1968, 12, 25)); // Paperwork crisis holidays.add(date(1968, 12, 31)); // Paperwork crisis holidays.add(date(1969, 2, 10)); // Snow holidays.add(date(1969, 3, 31)); // Death of Dwight Eisenhower holidays.add(date(1969, 7, 21)); // Lunar exploration holidays.add(date(1972, 12, 28)); // Death of Harry Truman holidays.add(date(1973, 1, 25)); // Death of Lyndon Johnson holidays.add(date(1977, 7, 14)); // Blackout holidays.add(date(1985, 9, 27)); // Hurricane Gloria holidays.add(date(1994, 4, 27)); // Death of Richard Nixon holidays.add(date(2001, 9, 11)); // 9/11 attack holidays.add(date(2001, 9, 12)); // 9/11 attack holidays.add(date(2001, 9, 13)); // 9/11 attack holidays.add(date(2001, 9, 14)); // 9/11 attack holidays.add(date(2004, 6, 11)); // Death of Ronald Reagan holidays.add(date(2007, 1, 2)); // Death of Gerald Ford holidays.add(date(2012, 10, 30)); // Hurricane Sandy removeSatSun(holidays); return ImmutableHolidayCalendar.of(HolidayCalendarIds.NYSE, holidays, SATURDAY, SUNDAY); } //------------------------------------------------------------------------- // generate JPTO // data sources // https://www.boj.or.jp/en/about/outline/holi.htm/ // http://web.archive.org/web/20110513190217/http://www.boj.or.jp/en/about/outline/holi.htm/ // http://web.archive.org/web/20130502031733/http://www.boj.or.jp/en/about/outline/holi.htm // http://www8.cao.go.jp/chosei/shukujitsu/gaiyou.html (law) // http://www.nao.ac.jp/faq/a0301.html (equinox) // http://eco.mtk.nao.ac.jp/koyomi/faq/holiday.html.en static ImmutableHolidayCalendar generateTokyo() { List<LocalDate> holidays = new ArrayList<>(2000); for (int year = 1950; year <= 2099; year++) { // new year holidays.add(date(year, 1, 1)); holidays.add(date(year, 1, 2)); holidays.add(date(year, 1, 3)); // coming of age if (year >= 2000) { holidays.add(date(year, 1, 1).with(dayOfWeekInMonth(2, MONDAY))); } else { holidays.add(bumpSunToMon(date(year, 1, 15))); } // national foundation if (year >= 1967) { holidays.add(bumpSunToMon(date(year, 2, 11))); } // vernal equinox (from 1948), 20th or 21st (predictions/facts 2000 to 2030) if (year == 2000 || year == 2001 || year == 2004 || year == 2005 || year == 2008 || year == 2009 || year == 2012 || year == 2013 || year == 2016 || year == 2017 || year == 2020 || year == 2021 || year == 2024 || year == 2025 || year == 2026 || year == 2028 || year == 2029 || year == 2030) { holidays.add(bumpSunToMon(date(year, 3, 20))); } else { holidays.add(bumpSunToMon(date(year, 3, 21))); } // showa (from 2007 onwards), greenery (from 1989 to 2006), emperor (before 1989) // http://news.bbc.co.uk/1/hi/world/asia-pacific/4543461.stm holidays.add(bumpSunToMon(date(year, 4, 29))); // constitution (from 1948) // greenery (from 2007 onwards), holiday between two other holidays before that (from 1985) // children (from 1948) if (year >= 1985) { holidays.add(bumpSunToMon(date(year, 5, 3))); holidays.add(bumpSunToMon(date(year, 5, 4))); holidays.add(bumpSunToMon(date(year, 5, 5))); if (year >= 2007 && (date(year, 5, 3).getDayOfWeek() == SUNDAY || date(year, 5, 4).getDayOfWeek() == SUNDAY)) { holidays.add(date(year, 5, 6)); } } else { holidays.add(bumpSunToMon(date(year, 5, 3))); holidays.add(bumpSunToMon(date(year, 5, 5))); } // marine if (year >= 2003) { holidays.add(date(year, 7, 1).with(dayOfWeekInMonth(3, MONDAY))); } else if (year >= 1996) { holidays.add(bumpSunToMon(date(year, 7, 20))); } // mountain if (year >= 2016) { holidays.add(bumpSunToMon(date(year, 8, 11))); } // aged if (year >= 2003) { holidays.add(date(year, 9, 1).with(dayOfWeekInMonth(3, MONDAY))); } else if (year >= 1966) { holidays.add(bumpSunToMon(date(year, 9, 15))); } // autumn equinox (from 1948), 22nd or 23rd (predictions/facts 2000 to 2030) if (year == 2012 || year == 2016 || year == 2020 || year == 2024 || year == 2028) { holidays.add(bumpSunToMon(date(year, 9, 22))); } else { holidays.add(bumpSunToMon(date(year, 9, 23))); } citizensDay(holidays, date(year, 9, 20), date(year, 9, 22)); citizensDay(holidays, date(year, 9, 21), date(year, 9, 23)); // health-sports if (year >= 2000) { holidays.add(date(year, 10, 1).with(dayOfWeekInMonth(2, MONDAY))); } else if (year >= 1966) { holidays.add(bumpSunToMon(date(year, 10, 10))); } // culture (from 1948) holidays.add(bumpSunToMon(date(year, 11, 3))); // labor (from 1948) holidays.add(bumpSunToMon(date(year, 11, 23))); // emperor (current emporer) if (year >= 1990) { holidays.add(bumpSunToMon(date(year, 12, 23))); } // new years eve - bank of Japan, but not national holiday holidays.add(bumpSunToMon(date(year, 12, 31))); } holidays.add(date(1959, 4, 10)); // marriage akihito holidays.add(date(1989, 2, 24)); // funeral showa holidays.add(date(1990, 11, 12)); // enthrone akihito holidays.add(date(1993, 6, 9)); // marriage naruhito removeSatSun(holidays); return ImmutableHolidayCalendar.of(HolidayCalendarIds.JPTO, holidays, SATURDAY, SUNDAY); } // extra day between two other holidays, appears to exclude weekends private static void citizensDay(List<LocalDate> holidays, LocalDate date1, LocalDate date2) { if (holidays.contains(date1) && holidays.contains(date2)) { if (date1.getDayOfWeek() == MONDAY || date1.getDayOfWeek() == TUESDAY || date1.getDayOfWeek() == WEDNESDAY) { holidays.add(date1.plusDays(1)); } } } //------------------------------------------------------------------------- // generate CATO // data sources // http://www.labour.gov.on.ca/english/es/pubs/guide/publicholidays.php // http://www.cra-arc.gc.ca/tx/hldys/menu-eng.html // http://www.tmxmoney.com/en/investor_tools/market_hours.html // http://www.statutoryholidayscanada.com/ // http://www.osc.gov.on.ca/en/SecuritiesLaw_csa_20151209_13-315_sra-closed-dates.htm static ImmutableHolidayCalendar generateToronto() { List<LocalDate> holidays = new ArrayList<>(2000); for (int year = 1950; year <= 2099; year++) { // new year (public) holidays.add(bumpToMon(date(year, 1, 1))); // family (public) if (year >= 2008) { holidays.add(first(year, 2).with(dayOfWeekInMonth(3, MONDAY))); } // good friday (public) holidays.add(easter(year).minusDays(2)); // victoria (public) holidays.add(date(year, 5, 25).with(TemporalAdjusters.previous(MONDAY))); // canada (public) holidays.add(bumpToMon(date(year, 7, 1))); // civic holidays.add(first(year, 8).with(dayOfWeekInMonth(1, MONDAY))); // labour (public) holidays.add(first(year, 9).with(dayOfWeekInMonth(1, MONDAY))); // thanksgiving (public) holidays.add(first(year, 10).with(dayOfWeekInMonth(2, MONDAY))); // remembrance holidays.add(bumpToMon(date(year, 11, 11))); // christmas (public) holidays.add(christmasBumpedSatSun(year)); // boxing (public) holidays.add(boxingDayBumpedSatSun(year)); } removeSatSun(holidays); return ImmutableHolidayCalendar.of(HolidayCalendarId.of("CATO"), holidays, SATURDAY, SUNDAY); } //------------------------------------------------------------------------- // generate DKCO // data sources // http://www.finansraadet.dk/Bankkunde/Pages/bankhelligdage.aspx // web archive history of those pages static ImmutableHolidayCalendar generateCopenhagen() { List<LocalDate> holidays = new ArrayList<>(2000); for (int year = 1950; year <= 2099; year++) { // new year holidays.add(date(year, 1, 1)); // maundy thursday holidays.add(easter(year).minusDays(3)); // good friday holidays.add(easter(year).minusDays(2)); // easter monday holidays.add(easter(year).plusDays(1)); // prayer day (Friday) holidays.add(easter(year).plusDays(26)); // ascension (Thursday) holidays.add(easter(year).plusDays(39)); // ascension + 1 (Friday) holidays.add(easter(year).plusDays(40)); // whit monday holidays.add(easter(year).plusDays(50)); // constitution holidays.add(date(year, 6, 5)); // christmas eve holidays.add(date(year, 12, 24)); // christmas holidays.add(date(year, 12, 25)); // boxing holidays.add(date(year, 12, 26)); // new years eve holidays.add(date(year, 12, 31)); } removeSatSun(holidays); return ImmutableHolidayCalendar.of(HolidayCalendarId.of("DKCO"), holidays, SATURDAY, SUNDAY); } //------------------------------------------------------------------------- // generate NOOS // data sources // http://www.oslobors.no/ob_eng/Oslo-Boers/About-Oslo-Boers/Opening-hours // http://www.oslobors.no/Oslo-Boers/Om-Oslo-Boers/AApningstider // web archive history of those pages static ImmutableHolidayCalendar generateOslo() { List<LocalDate> holidays = new ArrayList<>(2000); for (int year = 1950; year <= 2099; year++) { // new year holidays.add(date(year, 1, 1)); // maundy thursday holidays.add(easter(year).minusDays(3)); // good friday holidays.add(easter(year).minusDays(2)); // easter monday holidays.add(easter(year).plusDays(1)); // labour holidays.add(date(year, 5, 1)); // constitution holidays.add(date(year, 5, 17)); // ascension holidays.add(easter(year).plusDays(39)); // whit monday holidays.add(easter(year).plusDays(50)); // christmas eve holidays.add(date(year, 12, 24)); // christmas holidays.add(date(year, 12, 25)); // boxing holidays.add(date(year, 12, 26)); // new years eve holidays.add(date(year, 12, 31)); } removeSatSun(holidays); return ImmutableHolidayCalendar.of(HolidayCalendarId.of("NOOS"), holidays, SATURDAY, SUNDAY); } //------------------------------------------------------------------------- // generate PLWA // data sources# // http://isap.sejm.gov.pl/DetailsServlet?id=WDU19510040028 and linked pages // https://www.gpw.pl/dni_bez_sesji_en // http://jollyday.sourceforge.net/data/pl.html static ImmutableHolidayCalendar generateWarsaw() { // holiday law dates from 1951, but don't know situation before then, so ignore 1951 date List<LocalDate> holidays = new ArrayList<>(2000); for (int year = 1950; year <= 2099; year++) { // new year holidays.add(date(year, 1, 1)); // epiphany if (year < 1961 || year >= 2011) { holidays.add(date(year, 1, 6)); } // good friday holidays.add(easter(year).minusDays(2)); // easter monday holidays.add(easter(year).plusDays(1)); // state holidays.add(date(year, 5, 1)); // constitution if (year >= 1990) { holidays.add(date(year, 5, 3)); } // rebirth/national if (year < 1990) { holidays.add(date(year, 7, 22)); } // corpus christi holidays.add(easter(year).plusDays(60)); // assumption if (year < 1961 || year >= 1989) { holidays.add(date(year, 8, 15)); } // all saints holidays.add(date(year, 11, 1)); // independence if (year >= 1990) { holidays.add(date(year, 11, 11)); } // christmas (exchange) holidays.add(date(year, 12, 24)); // christmas holidays.add(date(year, 12, 25)); // boxing holidays.add(date(year, 12, 26)); // new years eve (exchange, rule based on sample data) LocalDate nyeve = date(year, 12, 31); if (nyeve.getDayOfWeek() == MONDAY || nyeve.getDayOfWeek() == THURSDAY || nyeve.getDayOfWeek() == FRIDAY) { holidays.add(nyeve); } } removeSatSun(holidays); return ImmutableHolidayCalendar.of(HolidayCalendarId.of("PLWA"), holidays, SATURDAY, SUNDAY); } //------------------------------------------------------------------------- // generate SEST // data sources - history of dates that STIBOR fixing occurred // http://www.riksbank.se/en/Interest-and-exchange-rates/search-interest-rates-exchange-rates/?g5-SEDP1MSTIBOR=on&from=2016-01-01&to=2016-10-05&f=Day&cAverage=Average&s=Comma#search static ImmutableHolidayCalendar generateStockholm() { List<LocalDate> holidays = new ArrayList<>(2000); for (int year = 1950; year <= 2099; year++) { // new year holidays.add(date(year, 1, 1)); // epiphany holidays.add(date(year, 1, 6)); // good friday holidays.add(easter(year).minusDays(2)); // easter monday holidays.add(easter(year).plusDays(1)); // labour holidays.add(date(year, 5, 1)); // ascension holidays.add(easter(year).plusDays(39)); // midsummer friday holidays.add(date(year, 6, 19).with(nextOrSame(FRIDAY))); // national if (year > 2005) { holidays.add(date(year, 6, 6)); } // christmas holidays.add(date(year, 12, 24)); // christmas holidays.add(date(year, 12, 25)); // boxing holidays.add(date(year, 12, 26)); // new years eve (fixings, rule based on sample data) holidays.add(date(year, 12, 31)); } removeSatSun(holidays); return ImmutableHolidayCalendar.of(HolidayCalendarId.of("SEST"), holidays, SATURDAY, SUNDAY); } //------------------------------------------------------------------------- // http://www.rba.gov.au/schedules-events/bank-holidays/bank-holidays-2016.html // http://www.rba.gov.au/schedules-events/bank-holidays/bank-holidays-2017.html // web archive history of those pages static ImmutableHolidayCalendar generateSydney() { List<LocalDate> holidays = new ArrayList<>(2000); for (int year = 1950; year <= 2099; year++) { // new year holidays.add(bumpToMon(date(year, 1, 1))); // australia day holidays.add(bumpToMon(date(year, 1, 26))); // good friday holidays.add(easter(year).minusDays(2)); // easter monday holidays.add(easter(year).plusDays(1)); // anzac day holidays.add(date(year, 4, 25)); // queen's birthday holidays.add(first(year, 6).with(dayOfWeekInMonth(2, MONDAY))); // bank holiday holidays.add(first(year, 8).with(dayOfWeekInMonth(1, MONDAY))); // labour day holidays.add(first(year, 10).with(dayOfWeekInMonth(1, MONDAY))); // christmas holidays.add(christmasBumpedSatSun(year)); // boxing holidays.add(boxingDayBumpedSatSun(year)); } removeSatSun(holidays); return ImmutableHolidayCalendar.of(HolidayCalendarId.of("AUSY"), holidays, SATURDAY, SUNDAY); } //------------------------------------------------------------------------- // http://www.gov.za/about-sa/public-holidays // http://www.gov.za/sites/www.gov.za/files/Act36of1994.pdf // http://www.gov.za/sites/www.gov.za/files/Act48of1995.pdf // 27th Dec when Tue http://www.gov.za/sites/www.gov.za/files/34881_proc72.pdf static ImmutableHolidayCalendar generateJohannesburg() { List<LocalDate> holidays = new ArrayList<>(2000); for (int year = 1950; year <= 2099; year++) { // from 1995 (act of 7 Dec 1994) // older act from 1952 not implemented here // new year holidays.add(bumpSunToMon(date(year, 1, 1))); // human rights day holidays.add(bumpSunToMon(date(year, 3, 21))); // good friday holidays.add(easter(year).minusDays(2)); // family day (easter monday) holidays.add(easter(year).plusDays(1)); // freedom day holidays.add(bumpSunToMon(date(year, 4, 27))); // workers day holidays.add(bumpSunToMon(date(year, 5, 1))); // youth day holidays.add(bumpSunToMon(date(year, 6, 16))); // womens day holidays.add(bumpSunToMon(date(year, 8, 9))); // heritage day holidays.add(bumpSunToMon(date(year, 9, 24))); // reconcilliation holidays.add(bumpSunToMon(date(year, 12, 16))); // christmas holidays.add(christmasBumpedSun(year)); // goodwill holidays.add(boxingDayBumpedSun(year)); } // mostly election days // http://www.gov.za/sites/www.gov.za/files/40125_proc%2045.pdf holidays.add(date(2016, 8, 3)); // http://www.gov.za/sites/www.gov.za/files/37376_proc13.pdf holidays.add(date(2014, 5, 7)); // http://www.gov.za/sites/www.gov.za/files/34127_proc27.pdf holidays.add(date(2011, 5, 18)); // http://www.gov.za/sites/www.gov.za/files/32039_17.pdf holidays.add(date(2009, 4, 22)); // http://www.gov.za/sites/www.gov.za/files/30900_7.pdf (moved human rights day) holidays.add(date(2008, 5, 2)); // http://www.gov.za/sites/www.gov.za/files/28442_0.pdf holidays.add(date(2006, 3, 1)); // http://www.gov.za/sites/www.gov.za/files/26075.pdf holidays.add(date(2004, 4, 14)); // http://www.gov.za/sites/www.gov.za/files/20032_0.pdf holidays.add(date(1999, 12, 31)); holidays.add(date(2000, 1, 1)); holidays.add(date(2000, 1, 2)); removeSatSun(holidays); return ImmutableHolidayCalendar.of(HolidayCalendarId.of("ZAJO"), holidays, SATURDAY, SUNDAY); } //------------------------------------------------------------------------- // http://www.magyarkozlony.hu/dokumentumok/b0d596a3e6ce15a2350a9e138c058a78dd8622d0/megtekintes (article 148) // http://www.mfa.gov.hu/NR/rdonlyres/18C1949E-D740-45E0-923A-BDFC81EC44C8/0/ListofHolidays2016.pdf // http://jollyday.sourceforge.net/data/hu.html // https://englishhungary.wordpress.com/2012/01/15/bridge-days/ // http://www.ucmsgroup.hu/newsletter/public-holiday-and-related-work-schedule-changes-in-2015/ // http://www.ucmsgroup.hu/newsletter/public-holiday-and-related-work-schedule-changes-in-2014/ static ImmutableHolidayCalendar generateBudapest() { List<LocalDate> holidays = new ArrayList<>(2000); Set<LocalDate> workDays = new HashSet<>(500); for (int year = 1950; year <= 2099; year++) { // new year addDateWithHungarianBridging(date(year, 1, 1), -1, 1, holidays, workDays); // national day addDateWithHungarianBridging(date(year, 3, 15), -2, 1, holidays, workDays); if (year >= 2017) { // good friday holidays.add(easter(year).minusDays(2)); } // easter monday holidays.add(easter(year).plusDays(1)); // labour day addDateWithHungarianBridging(date(year, 5, 1), 0, 1, holidays, workDays); // pentecost monday holidays.add(easter(year).plusDays(50)); // state foundation day addDateWithHungarianBridging(date(year, 8, 20), 0, -2, holidays, workDays); // national day addDateWithHungarianBridging(date(year, 10, 23), 0, -1, holidays, workDays); // all saints day addDateWithHungarianBridging(date(year, 11, 1), -3, 1, holidays, workDays); // christmas holidays.add(date(year, 12, 25)); holidays.add(date(year, 12, 26)); if (date(year, 12, 25).getDayOfWeek() == TUESDAY) { holidays.add(date(year, 12, 24)); workDays.add(date(year, 12, 15)); } else if (date(year, 12, 25).getDayOfWeek() == WEDNESDAY) { holidays.add(date(year, 12, 24)); holidays.add(date(year, 12, 27)); workDays.add(date(year, 12, 7)); workDays.add(date(year, 12, 21)); } else if (date(year, 12, 25).getDayOfWeek() == THURSDAY) { holidays.add(date(year, 12, 24)); } else if (date(year, 12, 25).getDayOfWeek() == FRIDAY) { holidays.add(date(year, 12, 24)); workDays.add(date(year, 12, 12)); } } // some Saturdays are work days addHungarianSaturdays(holidays, workDays); return ImmutableHolidayCalendar.of(HolidayCalendarId.of("HUBU"), holidays, SUNDAY, SUNDAY); } // an attempt to divine the official rules from the data available private static void addDateWithHungarianBridging( LocalDate date, int relativeWeeksTue, int relativeWeeksThu, List<LocalDate> holidays, Set<LocalDate> workDays) { DayOfWeek dow = date.getDayOfWeek(); switch (dow) { case MONDAY: case WEDNESDAY: case FRIDAY: holidays.add(date); return; case TUESDAY: holidays.add(date.minusDays(1)); holidays.add(date); workDays.add(date.plusDays(4).plusWeeks(relativeWeeksTue)); // a Saturday is now a workday return; case THURSDAY: holidays.add(date.plusDays(1)); holidays.add(date); workDays.add(date.plusDays(2).plusWeeks(relativeWeeksThu)); // a Saturday is now a workday return; case SATURDAY: case SUNDAY: return; } } private static void addHungarianSaturdays(List<LocalDate> holidays, Set<LocalDate> workDays) { // remove all saturdays and sundays removeSatSun(holidays); // add all saturdays LocalDate endDate = LocalDate.of(2099, 12, 31); LocalDate date = LocalDate.of(1950, 1, 7); while (date.isBefore(endDate)) { if (!workDays.contains(date)) { holidays.add(date); } date = date.plusDays(7); } } //------------------------------------------------------------------------- // generate MXMC // dates of published fixings - https://twitter.com/Banxico // http://www.banxico.org.mx/SieInternet/consultarDirectorioInternetAction.do?accion=consultarCuadro&idCuadro=CF111&locale=en // http://www.gob.mx/cms/uploads/attachment/file/161094/calendario_vacaciones2016.pdf static ImmutableHolidayCalendar generateMexicoCity() { List<LocalDate> holidays = new ArrayList<>(2000); for (int year = 1950; year <= 2099; year++) { // new year holidays.add(date(year, 1, 1)); // constitution holidays.add(first(year, 2).with(firstInMonth(MONDAY))); // president holidays.add(first(year, 3).with(firstInMonth(MONDAY)).plusWeeks(2)); // maundy thursday holidays.add(easter(year).minusDays(3)); // good friday holidays.add(easter(year).minusDays(2)); // labour holidays.add(date(year, 5, 1)); // independence holidays.add(date(year, 9, 16)); // dead holidays.add(date(year, 11, 2)); // revolution holidays.add(first(year, 11).with(firstInMonth(MONDAY)).plusWeeks(2)); // guadalupe holidays.add(date(year, 12, 12)); // christmas holidays.add(date(year, 12, 25)); } removeSatSun(holidays); return ImmutableHolidayCalendar.of(HolidayCalendarId.of("MXMC"), holidays, SATURDAY, SUNDAY); } // generate BRBD // http://www.planalto.gov.br/ccivil_03/leis/l0662.htm // http://www.planalto.gov.br/ccivil_03/Leis/L6802.htm // http://www.planalto.gov.br/ccivil_03/leis/2002/L10607.htm static ImmutableHolidayCalendar generateBrazil() { // base law is from 1949, reworded in 2002 List<LocalDate> holidays = new ArrayList<>(2000); for (int year = 1950; year <= 2099; year++) { // new year holidays.add(date(year, 1, 1)); // carnival holidays.add(easter(year).minusDays(48)); holidays.add(easter(year).minusDays(47)); // tiradentes holidays.add(date(year, 4, 21)); // good friday holidays.add(easter(year).minusDays(2)); // labour holidays.add(date(year, 5, 1)); // corpus christi holidays.add(easter(year).plusDays(60)); // independence holidays.add(date(year, 9, 7)); // aparedica if (year >= 1980) { holidays.add(date(year, 10, 12)); } // dead holidays.add(date(year, 11, 2)); // republic holidays.add(date(year, 11, 15)); // christmas holidays.add(date(year, 12, 25)); } removeSatSun(holidays); return ImmutableHolidayCalendar.of(HolidayCalendarId.of("BRBD"), holidays, SATURDAY, SUNDAY); } // generate CZPR // https://www.cnb.cz/en/public/media_service/schedules/media_svatky.html static ImmutableHolidayCalendar generatePrague() { // dates are fixed - no moving Sunday to Monday or similar List<LocalDate> holidays = new ArrayList<>(2000); for (int year = 1950; year <= 2099; year++) { // new year holidays.add(date(year, 1, 1)); // good friday if (year > 2015) { holidays.add(easter(year).minusDays(2)); } // easter monday holidays.add(easter(year).plusDays(1)); // may day holidays.add(date(year, 5, 1)); // liberation from fascism holidays.add(date(year, 5, 8)); // cyril and methodius holidays.add(date(year, 7, 5)); // jan hus holidays.add(date(year, 7, 6)); // statehood holidays.add(date(year, 9, 28)); // republic holidays.add(date(year, 10, 28)); // freedom and democracy holidays.add(date(year, 11, 17)); // christmas eve holidays.add(date(year, 12, 24)); // christmas holidays.add(date(year, 12, 25)); // boxing holidays.add(date(year, 12, 26)); } removeSatSun(holidays); return ImmutableHolidayCalendar.of(HolidayCalendarId.of("CZPR"), holidays, SATURDAY, SUNDAY); } //------------------------------------------------------------------------- // date private static LocalDate date(int year, int month, int day) { return LocalDate.of(year, month, day); } // bump to following Monday private static LocalDate bumpToMon(LocalDate date) { if (date.getDayOfWeek() == SATURDAY) { return date.plusDays(2); } else if (date.getDayOfWeek() == SUNDAY) { return date.plusDays(1); } return date; } // bump Sunday to following Monday private static LocalDate bumpSunToMon(LocalDate date) { if (date.getDayOfWeek() == SUNDAY) { return date.plusDays(1); } return date; } // bump to Saturday to Friday and Sunday to Monday private static LocalDate bumpToFriOrMon(LocalDate date) { if (date.getDayOfWeek() == SATURDAY) { return date.minusDays(1); } else if (date.getDayOfWeek() == SUNDAY) { return date.plusDays(1); } return date; } // christmas private static LocalDate christmasBumpedSatSun(int year) { LocalDate base = LocalDate.of(year, 12, 25); if (base.getDayOfWeek() == SATURDAY || base.getDayOfWeek() == SUNDAY) { return LocalDate.of(year, 12, 27); } return base; } // christmas (if Christmas is Sunday, moved to Monday) private static LocalDate christmasBumpedSun(int year) { LocalDate base = LocalDate.of(year, 12, 25); if (base.getDayOfWeek() == SUNDAY) { return LocalDate.of(year, 12, 26); } return base; } // boxing day private static LocalDate boxingDayBumpedSatSun(int year) { LocalDate base = LocalDate.of(year, 12, 26); if (base.getDayOfWeek() == SATURDAY || base.getDayOfWeek() == SUNDAY) { return LocalDate.of(year, 12, 28); } return base; } // boxing day (if Christmas is Sunday, boxing day moved from Monday to Tuesday) private static LocalDate boxingDayBumpedSun(int year) { LocalDate base = LocalDate.of(year, 12, 26); if (base.getDayOfWeek() == MONDAY) { return LocalDate.of(year, 12, 27); } return base; } // first of a month private static LocalDate first(int year, int month) { return LocalDate.of(year, month, 1); } // remove any holidays covered by Sat/Sun private static void removeSatSun(List<LocalDate> holidays) { holidays.removeIf(date -> date.getDayOfWeek() == SATURDAY || date.getDayOfWeek() == SUNDAY); } // apply bridging (Mon/Fri are holidays if Tue/Thu are) private static void applyBridging(List<LocalDate> holidays) { Set<LocalDate> additional1 = holidays.stream() .filter(date -> date.getDayOfWeek() == TUESDAY && !MonthDay.from(date).equals(MonthDay.of(1, 1))) .map(date -> date.minusDays(1)) .collect(toSet()); Set<LocalDate> additional2 = holidays.stream() .filter(date -> date.getDayOfWeek() == THURSDAY && !MonthDay.from(date).equals(MonthDay.of(12, 26))) .map(date -> date.plusDays(1)) .collect(toSet()); holidays.addAll(additional1); holidays.addAll(additional2); } // calculate easter day by Delambre static LocalDate easter(int year) { int a = year % 19; int b = year / 100; int c = year % 100; int d = b / 4; int e = b % 4; int f = (b + 8) / 25; int g = (b - f + 1) / 3; int h = (19 * a + b - d - g + 15) % 30; int i = c / 4; int k = c % 4; int l = (32 + 2 * e + 2 * i - h - k) % 7; int m = (a + 11 * h + 22 * l) / 451; int month = (h + l - 7 * m + 114) / 31; int day = ((h + l - 7 * m + 114) % 31) + 1; return LocalDate.of(year, month, day); } }