diff --git a/.docs/world.svg b/.docs/world.svg index 99d6473ec..854f25bd5 100644 --- a/.docs/world.svg +++ b/.docs/world.svg @@ -115,7 +115,7 @@ - + Brunei Darussalam diff --git a/jollyday-core/src/main/java/de/focus_shift/jollyday/core/HolidayCalendar.java b/jollyday-core/src/main/java/de/focus_shift/jollyday/core/HolidayCalendar.java index 9d2a4027f..3c5c5de85 100644 --- a/jollyday-core/src/main/java/de/focus_shift/jollyday/core/HolidayCalendar.java +++ b/jollyday-core/src/main/java/de/focus_shift/jollyday/core/HolidayCalendar.java @@ -14,7 +14,7 @@ public enum HolidayCalendar { ANTARCTICA("AQ"), AFGHANISTAN("AF"), ALBANIA("AL"), ALGERIA("DZ"), ANDORRA("AD"), ANTIGUA_AND_BARBUDA("AG"), ANGOLA("AO"), ARGENTINA("AR"), ARMENIA("AM"), AZERBAIJAN("AZ"), AUSTRALIA("AU"), AUSTRIA("AT"), - BAHAMAS("BS"), BANGLADESH("BD"), BAHRAIN("BH"), BARBADOS("BB"), BELARUS("BY"), BELGIUM("BE"), BELIZE("BZ"), BENIN("BJ"), BERMUDA("BM"), BOLIVIA("BO"), BOSNIA_HERZIGOWINA("BA"), BOTSWANA("BW"), BRAZIL("BR"), BRITISH_VIRGIN_ISLANDS("VG"), BULGARIA("BG"), BURUNDI("BI"), BURKINA_FASO("BF"), + BAHAMAS("BS"), BANGLADESH("BD"), BAHRAIN("BH"), BARBADOS("BB"), BELARUS("BY"), BELGIUM("BE"), BELIZE("BZ"), BENIN("BJ"), BERMUDA("BM"), BOLIVIA("BO"), BOSNIA_HERZIGOWINA("BA"), BOTSWANA("BW"), BRAZIL("BR"), BRUNEI("BN"), BRITISH_VIRGIN_ISLANDS("VG"), BULGARIA("BG"), BURUNDI("BI"), BURKINA_FASO("BF"), CAMEROON("CM"), CANADA(Locale.CANADA.getCountry()), CAPE_VERDE("CV"), CAYMAN_ISLANDS("KY"), CENTRAL_AFRICAN_REPUBLIC("CF"), CHAD("TD"), CHILE("CL"), COLOMBIA("CO"), CONGO("CD"), CONGO_REPUBLIC("CG"), COMOROS("KM"), COSTA_RICA("CR"), CROATIA("HR"), CUBA("CU"), CZECH_REPUBLIC("CZ"), CYPRUS("CY"), DENMARK("DK"), DJIBOUTI("DJ"), DOMINICA("DM"), DOW_JONES_STOXX("DJ_STOXX"), ECUADOR("EC"), EGYPT("EG"), EL_SALVADOR("SV"), ERITREA("ER"), ESTONIA("EE"), ETHIOPIA("ET"), EQUATORIAL_GUINEA("GQ"), diff --git a/jollyday-core/src/main/java/de/focus_shift/jollyday/core/parser/impl/IslamicHolidayParser.java b/jollyday-core/src/main/java/de/focus_shift/jollyday/core/parser/impl/IslamicHolidayParser.java index a085b206b..2e49b38be 100644 --- a/jollyday-core/src/main/java/de/focus_shift/jollyday/core/parser/impl/IslamicHolidayParser.java +++ b/jollyday-core/src/main/java/de/focus_shift/jollyday/core/parser/impl/IslamicHolidayParser.java @@ -48,6 +48,8 @@ public class IslamicHolidayParser implements HolidayParser { new CalculateRelativeDatesFromChronologyWithinGregorianYear(8, 15, HIJRAH, 0).apply(year); case RAMADAN -> new CalculateRelativeDatesFromChronologyWithinGregorianYear(9, 1, HIJRAH, 0).apply(year); + case NUZUL_AL_QURAN -> + new CalculateRelativeDatesFromChronologyWithinGregorianYear(9, 17, HIJRAH, 0).apply(year); case LAILAT_AL_QADR -> new CalculateRelativeDatesFromChronologyWithinGregorianYear(9, 27, HIJRAH, 0).apply(year); case JUMUATUL_WIDA -> diff --git a/jollyday-core/src/main/java/de/focus_shift/jollyday/core/spi/IslamicHolidayConfiguration.java b/jollyday-core/src/main/java/de/focus_shift/jollyday/core/spi/IslamicHolidayConfiguration.java index a1ed75728..b43af9395 100644 --- a/jollyday-core/src/main/java/de/focus_shift/jollyday/core/spi/IslamicHolidayConfiguration.java +++ b/jollyday-core/src/main/java/de/focus_shift/jollyday/core/spi/IslamicHolidayConfiguration.java @@ -25,6 +25,7 @@ enum IslamicHolidayType { LAILAT_AL_MIRAJ, LAILAT_AL_BARAT, RAMADAN, + NUZUL_AL_QURAN, JUMUATUL_WIDA, LAILAT_AL_QADR, RAMADAN_END, diff --git a/jollyday-core/src/main/resources/descriptions/holiday_descriptions.properties b/jollyday-core/src/main/resources/descriptions/holiday_descriptions.properties index 3c1d3a44f..7788c6b12 100644 --- a/jollyday-core/src/main/resources/descriptions/holiday_descriptions.properties +++ b/jollyday-core/src/main/resources/descriptions/holiday_descriptions.properties @@ -499,6 +499,7 @@ holiday.description.ST_ROBERT_BELLARMINE holiday.description.ST_SEBASTIAN = Saint Sebastian holiday.description.ST_URSULA = St. Ursulas's Day holiday.description.ST_VITUS = St.Vitus' Day +holiday.description.SULTANS_BIRTHDAY = Sultan's Birthday holiday.description.SUMMER_BANK_HOLIDAY = Summer Bank Holiday holiday.description.SYRIAN_REVOLUTION_DAY = Syrian Revolution Day holiday.description.TARANAKI_ANNIVERSARY = Taranaki Anniversary @@ -604,6 +605,7 @@ holiday.description.islamic.LAILAT_AL_MIRAJ holiday.description.islamic.LAILAT_AL_QADR = Laylat al-Qadr holiday.description.islamic.MAWLID_AN_NABI = Mawlid an-Nabi holiday.description.islamic.NEWYEAR = Islamic New Year +holiday.description.islamic.NUZUL_AL_QURAN = Nuzul Al-Quran holiday.description.islamic.RAMADAN = Ramadan holiday.description.islamic.RAMADAN_END = Ramadan End holiday.description.islamic.TASUA = Tasua diff --git a/jollyday-core/src/main/resources/descriptions/holiday_descriptions_de.properties b/jollyday-core/src/main/resources/descriptions/holiday_descriptions_de.properties index ff9d92c0a..6b8aecf14 100644 --- a/jollyday-core/src/main/resources/descriptions/holiday_descriptions_de.properties +++ b/jollyday-core/src/main/resources/descriptions/holiday_descriptions_de.properties @@ -499,6 +499,7 @@ holiday.description.ST_ROBERT_BELLARMINE holiday.description.ST_SEBASTIAN = Heiliger Sebastian holiday.description.ST_URSULA = St. Ursulas-Tag holiday.description.ST_VITUS = St.Vitus' Tag +holiday.description.SULTANS_BIRTHDAY = Geburtstag des Sultans holiday.description.SUMMER_BANK_HOLIDAY = Summer Bank Holiday holiday.description.SYRIAN_REVOLUTION_DAY = Syrischer Revolutionstag holiday.description.TARANAKI_ANNIVERSARY = Taranaki Anniversary @@ -604,6 +605,7 @@ holiday.description.islamic.LAILAT_AL_MIRAJ holiday.description.islamic.LAILAT_AL_QADR = Laylat al-Qadr holiday.description.islamic.MAWLID_AN_NABI = Mawlid an-Nabi holiday.description.islamic.NEWYEAR = Islamisches Neujahr +holiday.description.islamic.NUZUL_AL_QURAN = Nuzul al-Quran holiday.description.islamic.RAMADAN = Ramadan holiday.description.islamic.RAMADAN_END = Ramadan End holiday.description.islamic.TASUA = Tasua diff --git a/jollyday-core/src/main/resources/descriptions/holiday_descriptions_el.properties b/jollyday-core/src/main/resources/descriptions/holiday_descriptions_el.properties index 97b54fb3c..47e574bf3 100644 --- a/jollyday-core/src/main/resources/descriptions/holiday_descriptions_el.properties +++ b/jollyday-core/src/main/resources/descriptions/holiday_descriptions_el.properties @@ -499,6 +499,7 @@ holiday.description.ST_ROBERT_BELLARMINE holiday.description.ST_SEBASTIAN = Άγιος Σεβαστιανός holiday.description.ST_URSULA = Ημέρα της Αγίας Ούρσουλας holiday.description.ST_VITUS = Ημέρα του Αγίου Βίτου +holiday.description.SULTANS_BIRTHDAY = Γενέθλια του Σουλτάνου holiday.description.SUMMER_BANK_HOLIDAY = Καλοκαιρινές διακοπές holiday.description.SYRIAN_REVOLUTION_DAY = Ημέρα της Συριακής Επανάστασης holiday.description.TARANAKI_ANNIVERSARY = Επέτειος Ταρανάκη @@ -604,6 +605,7 @@ holiday.description.islamic.LAILAT_AL_MIRAJ holiday.description.islamic.LAILAT_AL_QADR = Laylat al-Qadr holiday.description.islamic.MAWLID_AN_NABI = Mawlid an-Nabi holiday.description.islamic.NEWYEAR = Ισλαμική Πρωτοχρονιά +holiday.description.islamic.NUZUL_AL_QURAN = Νουζούλ Αλ-Κοράν holiday.description.islamic.RAMADAN = Ραμαζάνι holiday.description.islamic.RAMADAN_END = Τέλος του Ραμαζανιού holiday.description.islamic.TASUA = Tasua diff --git a/jollyday-core/src/main/resources/descriptions/holiday_descriptions_fr.properties b/jollyday-core/src/main/resources/descriptions/holiday_descriptions_fr.properties index 70214a0ad..208c8f621 100644 --- a/jollyday-core/src/main/resources/descriptions/holiday_descriptions_fr.properties +++ b/jollyday-core/src/main/resources/descriptions/holiday_descriptions_fr.properties @@ -499,6 +499,7 @@ holiday.description.ST_ROBERT_BELLARMINE holiday.description.ST_SEBASTIAN = St. Sebastian holiday.description.ST_URSULA = Jour de la Saint Ursule holiday.description.ST_VITUS = St. Vitus' Day +holiday.description.SULTANS_BIRTHDAY = Anniversaire du Sultan holiday.description.SUMMER_BANK_HOLIDAY = Summer Bank Holiday holiday.description.SYRIAN_REVOLUTION_DAY = Journée de la révolution syrienne holiday.description.TARANAKI_ANNIVERSARY = Taranaki Anniversary @@ -604,6 +605,7 @@ holiday.description.islamic.LAILAT_AL_MIRAJ holiday.description.islamic.LAILAT_AL_QADR = Laylat al-Qadr holiday.description.islamic.MAWLID_AN_NABI = Mawlid an-Nabi holiday.description.islamic.NEWYEAR = Islamic New Year +holiday.description.islamic.NUZUL_AL_QURAN = Nuzul Al-Quran holiday.description.islamic.RAMADAN = Ramadan holiday.description.islamic.RAMADAN_END = Ramadan End holiday.description.islamic.TASUA = Tasua diff --git a/jollyday-core/src/main/resources/descriptions/holiday_descriptions_nl.properties b/jollyday-core/src/main/resources/descriptions/holiday_descriptions_nl.properties index 7a00927fd..e5d1fdbaa 100644 --- a/jollyday-core/src/main/resources/descriptions/holiday_descriptions_nl.properties +++ b/jollyday-core/src/main/resources/descriptions/holiday_descriptions_nl.properties @@ -499,6 +499,7 @@ holiday.description.ST_ROBERT_BELLARMINE holiday.description.ST_SEBASTIAN = Saint Sebastian holiday.description.ST_URSULA = Dag van St. Ursulas holiday.description.ST_VITUS = St.Vitus' dag +holiday.description.SULTANS_BIRTHDAY = Verjaardag van de Sultan holiday.description.SUMMER_BANK_HOLIDAY = Summer Bank Holiday holiday.description.SYRIAN_REVOLUTION_DAY = Dag van de Syrische Revolutie holiday.description.TARANAKI_ANNIVERSARY = Taranaki Anniversary @@ -606,6 +607,7 @@ holiday.description.islamic.LAILAT_AL_MIRAJ holiday.description.islamic.LAILAT_AL_QADR = Laylat al-Qadr holiday.description.islamic.MAWLID_AN_NABI = Mawlid an-Nabi holiday.description.islamic.NEWYEAR = Islamitisch nieuwjaar +holiday.description.islamic.NUZUL_AL_QURAN = Nuzul al-Koran holiday.description.islamic.RAMADAN = Ramadan holiday.description.islamic.RAMADAN_END = Einde Ramadan holiday.description.islamic.TASUA = Tasua diff --git a/jollyday-core/src/main/resources/descriptions/holiday_descriptions_pt.properties b/jollyday-core/src/main/resources/descriptions/holiday_descriptions_pt.properties index 4806d3660..f082d0d4d 100644 --- a/jollyday-core/src/main/resources/descriptions/holiday_descriptions_pt.properties +++ b/jollyday-core/src/main/resources/descriptions/holiday_descriptions_pt.properties @@ -499,6 +499,7 @@ holiday.description.ST_ROBERT_BELLARMINE holiday.description.ST_SEBASTIAN = São Sebastião holiday.description.ST_URSULA = Dia de Santa Úrsula holiday.description.ST_VITUS = Dia de St. Vitus +holiday.description.SULTANS_BIRTHDAY = Aniversário do Sultão holiday.description.SUMMER_BANK_HOLIDAY = Summer Bank Holiday holiday.description.SYRIAN_REVOLUTION_DAY = Dia da Revolução Síria holiday.description.TARANAKI_ANNIVERSARY = Taranaki Anniversary @@ -604,6 +605,7 @@ holiday.description.islamic.LAILAT_AL_MIRAJ holiday.description.islamic.LAILAT_AL_QADR = Laylat al-Qadr holiday.description.islamic.MAWLID_AN_NABI = Mawlid an-Nabi holiday.description.islamic.NEWYEAR = Ano Novo Islâmico +holiday.description.islamic.NUZUL_AL_QURAN = Nuzul Al-Corão holiday.description.islamic.RAMADAN = Ramadão holiday.description.islamic.RAMADAN_END = Fim do Ramadão holiday.description.islamic.TASUA = Tasua diff --git a/jollyday-core/src/main/resources/descriptions/holiday_descriptions_sv.properties b/jollyday-core/src/main/resources/descriptions/holiday_descriptions_sv.properties index 51ab35114..f895340e9 100644 --- a/jollyday-core/src/main/resources/descriptions/holiday_descriptions_sv.properties +++ b/jollyday-core/src/main/resources/descriptions/holiday_descriptions_sv.properties @@ -496,6 +496,7 @@ holiday.description.ST_ROBERT_BELLARMINE holiday.description.ST_SEBASTIAN = Saint Sebastian holiday.description.ST_URSULA = Sankt Ursulas dag holiday.description.ST_VITUS = St.Vitus' Day +holiday.description.SULTANS_BIRTHDAY = Sultanens födelsedag holiday.description.SUMMER_BANK_HOLIDAY = Summer Bank Holiday holiday.description.SYRIAN_REVOLUTION_DAY = Syriska revolutionens dag holiday.description.TARANAKI_ANNIVERSARY = Taranaki Anniversary @@ -601,6 +602,7 @@ holiday.description.islamic.LAILAT_AL_MIRAJ holiday.description.islamic.LAILAT_AL_QADR = Laylat al-Qadr holiday.description.islamic.MAWLID_AN_NABI = Mawlid an-Nabi holiday.description.islamic.NEWYEAR = Islamic New Year +holiday.description.islamic.NUZUL_AL_QURAN = Nuzul al-Koran holiday.description.islamic.RAMADAN = Ramadan holiday.description.islamic.RAMADAN_END = Ramadan End holiday.description.islamic.TASUA = Tasua diff --git a/jollyday-core/src/main/resources/focus_shift.de/jollyday/schema/holiday/holiday.xsd b/jollyday-core/src/main/resources/focus_shift.de/jollyday/schema/holiday/holiday.xsd index 02153776c..f6c4efd64 100644 --- a/jollyday-core/src/main/resources/focus_shift.de/jollyday/schema/holiday/holiday.xsd +++ b/jollyday-core/src/main/resources/focus_shift.de/jollyday/schema/holiday/holiday.xsd @@ -163,6 +163,7 @@ + diff --git a/jollyday-core/src/main/resources/holidays/Holidays_bn.xml b/jollyday-core/src/main/resources/holidays/Holidays_bn.xml new file mode 100644 index 000000000..591305c15 --- /dev/null +++ b/jollyday-core/src/main/resources/holidays/Holidays_bn.xml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + https://en.wikipedia.org/wiki/Public_holidays_in_Brunei + https://en.wikipedia.org/wiki/ISO_3166-2:BN + https://www.iso.org/obp/ui/#iso:code:3166:BN + + diff --git a/jollyday-core/src/test/java/de/focus_shift/jollyday/core/parser/impl/IslamicHolidayParserTest.java b/jollyday-core/src/test/java/de/focus_shift/jollyday/core/parser/impl/IslamicHolidayParserTest.java index b65819452..043cf8d9f 100644 --- a/jollyday-core/src/test/java/de/focus_shift/jollyday/core/parser/impl/IslamicHolidayParserTest.java +++ b/jollyday-core/src/test/java/de/focus_shift/jollyday/core/parser/impl/IslamicHolidayParserTest.java @@ -55,6 +55,7 @@ private Stream islamicHolidaysWithLocalDates() { "2022-02-28", // LAILAT_AL_MIRAJ "2022-03-18", // LAILAT_AL_BARAT "2022-04-02", // RAMADAN + "2022-04-18", // NUZUL_AL_QURAN (17 Ramadan) "2022-04-29", // JUMUATUL_WIDA (Friday before Ramadan ends) "2022-04-28", // LAILAT_AL_QADR "2022-05-01", // RAMADAN_END diff --git a/jollyday-jackson/src/main/java/de/focus_shift/jollyday/jackson/mapping/IslamicHolidayType.java b/jollyday-jackson/src/main/java/de/focus_shift/jollyday/jackson/mapping/IslamicHolidayType.java index d25a16adf..a86ed948e 100644 --- a/jollyday-jackson/src/main/java/de/focus_shift/jollyday/jackson/mapping/IslamicHolidayType.java +++ b/jollyday-jackson/src/main/java/de/focus_shift/jollyday/jackson/mapping/IslamicHolidayType.java @@ -9,6 +9,7 @@ public enum IslamicHolidayType { LAILAT_AL_MIRAJ, LAILAT_AL_BARAT, RAMADAN, + NUZUL_AL_QURAN, JUMUATUL_WIDA, LAILAT_AL_QADR, RAMADAN_END, diff --git a/jollyday-tests/src/test/java/de/focus_shift/jollyday/tests/country/HolidayBNTest.java b/jollyday-tests/src/test/java/de/focus_shift/jollyday/tests/country/HolidayBNTest.java new file mode 100644 index 000000000..95307d90b --- /dev/null +++ b/jollyday-tests/src/test/java/de/focus_shift/jollyday/tests/country/HolidayBNTest.java @@ -0,0 +1,92 @@ +package de.focus_shift.jollyday.tests.country; + +import de.focus_shift.jollyday.core.Holiday; +import de.focus_shift.jollyday.core.HolidayManager; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; +import org.junit.jupiter.params.provider.ValueSource; + +import java.time.LocalDate; +import java.time.Year; +import java.util.Set; + +import static de.focus_shift.jollyday.core.HolidayCalendar.BRUNEI; +import static de.focus_shift.jollyday.core.ManagerParameters.create; +import static de.focus_shift.jollyday.tests.CalendarCheckerApi.assertFor; +import static java.time.Month.DECEMBER; +import static java.time.Month.FEBRUARY; +import static java.time.Month.JANUARY; +import static java.time.Month.JULY; +import static java.time.Month.MAY; +import static org.assertj.core.api.Assertions.assertThat; + +class HolidayBNTest { + + // Java's HijrahChronology (Umm al-Qura) only covers roughly 1882-2174, so Islamic holidays + // are asserted within this window (see HolidayKWTest). + private static final Year YEAR_FROM = Year.of(1900); + private static final Year YEAR_TO = Year.of(2173); + + @Test + void ensuresHolidays() { + assertFor(BRUNEI) + // Fixed Gregorian holidays + .hasFixedHoliday("NEW_YEAR", JANUARY, 1).validBetween(YEAR_FROM, YEAR_TO).and() + .hasFixedHoliday("NATIONAL_DAY", FEBRUARY, 23).validBetween(YEAR_FROM, YEAR_TO).and() + .hasFixedHoliday("ARMED_FORCES_DAY", MAY, 31).validBetween(YEAR_FROM, YEAR_TO).and() + .hasFixedHoliday("SULTANS_BIRTHDAY", JULY, 15).validBetween(YEAR_FROM, YEAR_TO).and() + .hasFixedHoliday("CHRISTMAS", DECEMBER, 25).validBetween(YEAR_FROM, YEAR_TO).and() + // Islamic (Hijri) holidays + .hasIslamicHoliday("NEWYEAR").validBetween(YEAR_FROM, YEAR_TO).and() + .hasIslamicHoliday("MAWLID_AN_NABI").validBetween(YEAR_FROM, YEAR_TO).and() + .hasIslamicHoliday("LAILAT_AL_MIRAJ").validBetween(YEAR_FROM, YEAR_TO).and() + .hasIslamicHoliday("RAMADAN").validBetween(YEAR_FROM, YEAR_TO).and() + .hasIslamicHoliday("NUZUL_AL_QURAN").validBetween(YEAR_FROM, YEAR_TO).and() + .hasIslamicHoliday("ID_AL_FITR").validBetween(YEAR_FROM, YEAR_TO).and() + .hasIslamicHoliday("ID_AL_FITR_2").validBetween(YEAR_FROM, YEAR_TO).and() + .hasIslamicHoliday("ID_AL_FITR_3").validBetween(YEAR_FROM, YEAR_TO).and() + .hasIslamicHoliday("ID_UL_ADHA").validBetween(YEAR_FROM, YEAR_TO) + .check(); + } + + @ParameterizedTest + @CsvSource({ + "2022, 2, 1", + "2023, 1, 22", + "2024, 2, 10", + "2025, 1, 29", + "2026, 2, 17", + "2027, 2, 6", + }) + void ensuresChineseNewYear(final int year, final int month, final int day) { + final HolidayManager holidayManager = HolidayManager.getInstance(create(BRUNEI)); + final Set holidays = holidayManager.getHolidays(Year.of(year)); + + assertThat(holidays) + .filteredOn(holiday -> holiday.getPropertiesKey().equals("CHINESE_NEW_YEAR")) + .extracting(Holiday::getDate) + .containsExactly(LocalDate.of(year, month, day)); + } + + @ParameterizedTest + @ValueSource(ints = {2022, 2023, 2024, 2025, 2026, 2027}) + void ensuresNuzulAlQuranIsSixteenDaysAfterStartOfRamadan(final int year) { + final HolidayManager holidayManager = HolidayManager.getInstance(create(BRUNEI)); + final Set holidays = holidayManager.getHolidays(Year.of(year)); + + final LocalDate ramadan = dateOf(holidays, "islamic.RAMADAN"); + final LocalDate nuzul = dateOf(holidays, "islamic.NUZUL_AL_QURAN"); + + // 1 Ramadan -> 17 Ramadan is exactly 16 days. + assertThat(nuzul).isEqualTo(ramadan.plusDays(16)); + } + + private static LocalDate dateOf(final Set holidays, final String propertyKey) { + return holidays.stream() + .filter(holiday -> holiday.getPropertiesKey().equals(propertyKey)) + .map(Holiday::getDate) + .findFirst() + .orElseThrow(() -> new AssertionError("Holiday not found: " + propertyKey)); + } +}