| name | Add Subdivision |
| description | Add subdivision holiday configurations based on ISO 3166-2 codes |
How to Add Subdivisions
This guide explains how to add subdivision holiday configurations for subdivisions (states, provinces, regions) based on ISO 3166-2 codes.
Overview
Subdivisions allow you to define holidays that are specific to certain subdivision within a country. For example, in Germany, Bavaria (BY) has different holidays than Berlin (BE).
File Location
Edit the country's XML file: jollyday-core/src/main/resources/holidays/Holidays_[country_code].xml
Important: The [country_code] must be lowercase (e.g., Holidays_de.xml for Germany, Holidays_us.xml for United States).
ISO 3166-2 Codes
Subdivision codes follow the ISO 3166-2 standard:
| Format | Example | Meaning |
|---|
XX-YY | DE-BY | Germany - Bavaria |
XX-YY-ZZ | DE-BY-MU | Germany - Bavaria - Munich |
The subdivision hierarchy attribute uses only the regional part (without the country prefix).
Basic Structure
<SubConfigurations hierarchy="[subdivision_code]" description="[Subdivision Name]">
<Holidays>
</Holidays>
</SubConfigurations>
Example - Germany (Baden-Württemberg)
<SubConfigurations hierarchy="bw" description="Baden-Württemberg">
<Holidays>
<Fixed month="JANUARY" day="6" descriptionPropertiesKey="EPIPHANY"/>
<Fixed month="NOVEMBER" day="1" descriptionPropertiesKey="ALL_SAINTS"/>
<ChristianHoliday type="CORPUS_CHRISTI"/>
</Holidays>
</SubConfigurations>
Adding a New Subdivision
Step 1: Find the ISO 3166-2 Code
Look up the subdivision code:
Example - Germany codes:
| Code | Region |
|---|
bw | Baden-Württemberg |
by | Bavaria |
be | Berlin |
bb | Brandenburg |
he | Hesse |
nw | North Rhine-Westphalia |
Step 2: Add SubConfigurations Element
Insert the subdivision in your country's XML file:
<SubConfigurations hierarchy="[subdivision_code]" description="[Subdivision Name]">
<Holidays>
<Fixed month="JANUARY" day="6" descriptionPropertiesKey="EPIPHANY"/>
</Holidays>
</SubConfigurations>
Step 3: Add Sources (Optional)
Document the source of subdivision holiday information:
<SubConfigurations hierarchy="[subdivision_code]" description="[Subdivision Name]">
<Holidays>
<Fixed month="JANUARY" day="6" descriptionPropertiesKey="EPIPHANY"/>
</Holidays>
<Sources>
<Source>https://www.region-official-website.gov/holidays</Source>
</Sources>
</SubConfigurations>
Nested Subdivisions
Subdivisions can be nested for more granular regions (cities within states):
<SubConfigurations hierarchy="by" description="Bavaria">
<Holidays>
<Fixed month="JANUARY" day="6" descriptionPropertiesKey="EPIPHANY"/>
</Holidays>
<SubConfigurations hierarchy="mu" description="Munich">
<Holidays>
<Fixed month="AUGUST" day="15" descriptionPropertiesKey="ASSUMPTION_DAY"/>
</Holidays>
</SubConfigurations>
<SubConfigurations hierarchy="ag" description="Augsburg">
<Holidays>
<Fixed month="AUGUST" day="8" descriptionPropertiesKey="PEACE"/>
<Fixed month="AUGUST" day="15" descriptionPropertiesKey="ASSUMPTION_DAY"/>
</Holidays>
</SubConfigurations>
</SubConfigurations>
Complete Example - Germany
<?xml version="1.0" encoding="UTF-8"?>
<Configuration hierarchy="de" description="Germany"
xmlns="https://focus_shift.de/jollyday/schema/holiday"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://focus_shift.de/jollyday/schema/holiday https://focus_shift.de/jollyday/schema/holiday/holiday.xsd">
<Holidays>
<Fixed month="JANUARY" day="1" descriptionPropertiesKey="NEW_YEAR"/>
<Fixed month="MAY" day="1" descriptionPropertiesKey="LABOUR_DAY"/>
<Fixed month="DECEMBER" day="25" descriptionPropertiesKey="FIRST_CHRISTMAS_DAY"/>
<Fixed month="DECEMBER" day="26" descriptionPropertiesKey="SECOND_CHRISTMAS_DAY"/>
<ChristianHoliday type="GOOD_FRIDAY"/>
<ChristianHoliday type="EASTER_MONDAY"/>
<ChristianHoliday type="ASCENSION_DAY"/>
<ChristianHoliday type="WHIT_MONDAY"/>
</Holidays>
<Sources>
<Source>https://en.wikipedia.org/wiki/Public_holidays_in_Germany</Source>
<Source of="ISO 3166-2">https://en.wikipedia.org/wiki/ISO_3166-2:DE</Source>
</Sources>
<SubConfigurations hierarchy="by" description="Bavaria">
<Holidays>
<Fixed month="JANUARY" day="6" descriptionPropertiesKey="EPIPHANY"/>
<Fixed month="NOVEMBER" day="1" descriptionPropertiesKey="ALL_SAINTS"/>
<ChristianHoliday type="CORPUS_CHRISTI"/>
</Holidays>
</SubConfigurations>
<SubConfigurations hierarchy="be" description="Berlin">
<Holidays>
<Fixed month="MARCH" day="8" descriptionPropertiesKey="INTERNATIONAL_WOMAN" validFrom="2019"/>
</Holidays>
</SubConfigurations>
</Configuration>
Holiday Types in Subdivisions
All holiday types can be used in subdivisions:
<SubConfigurations hierarchy="[subdivision_code]" description="[Subdivision Name]">
<Holidays>
<Fixed month="JANUARY" day="6" descriptionPropertiesKey="EPIPHANY"/>
<FixedWeekday which="FIRST" weekday="MONDAY" month="MAY" descriptionPropertiesKey="LABOUR_DAY"/>
<ChristianHoliday type="CORPUS_CHRISTI"/>
<RelativeToFixed descriptionPropertiesKey="REPENTANCE_PRAYER">
<Weekday>WEDNESDAY</Weekday>
<When>BEFORE</When>
<Date month="NOVEMBER" day="23"/>
</RelativeToFixed>
</Holidays>
</SubConfigurations>
Validity Periods
Subdivision holidays can have validity periods:
<SubConfigurations hierarchy="[subdivision_code]" description="[Subdivision Name]">
<Holidays>
<Fixed month="MARCH" day="8" descriptionPropertiesKey="INTERNATIONAL_WOMAN" validFrom="2019"/>
<Fixed month="MAY" day="8" descriptionPropertiesKey="LIBERATION" validFrom="2020" validTo="2020"/>
<Fixed month="OCTOBER" day="31" descriptionPropertiesKey="REFORMATION_DAY" validFrom="2018"/>
</Holidays>
</SubConfigurations>
Testing Subdivisions
Tests for subdivisions use the .inSubdivision() method chained after the holiday assertion:
import static de.focus_shift.jollyday.core.HolidayCalendar.GERMANY;
import static de.focus_shift.jollyday.tests.CalendarCheckerApi.assertFor;
import static java.time.Month.JANUARY;
@Test
void ensuresBavarianHolidays() {
assertFor(GERMANY)
.hasFixedHoliday("EPIPHANY", JANUARY, 6).inSubdivision("by").and()
.hasFixedHoliday("ALL_SAINTS", NOVEMBER, 1).inSubdivision("by").and()
.hasChristianHoliday("CORPUS_CHRISTI").inSubdivision("by")
.check();
}
@Test
void ensuresBadenWurttembergHolidays() {
assertFor(GERMANY)
.hasFixedHoliday("EPIPHANY", JANUARY, 6).inSubdivision("bw")
.check();
}
@Test
void ensuresNestedSubdivisions() {
assertFor(GERMANY)
.hasFixedHoliday("ASSUMPTION_DAY", AUGUST, 15).inSubdivision("by", "mu")
.check();
}
@Test
void ensuresMultipleSubdivisions() {
assertFor(GERMANY)
.hasFixedHoliday("ALL_SAINTS", NOVEMBER, 1).inSubdivision("bw").and()
.hasFixedHoliday("ALL_SAINTS", NOVEMBER, 1).inSubdivision("by").and()
.hasFixedHoliday("ALL_SAINTS", NOVEMBER, 1).inSubdivision("nw")
.check();
}
inSubdivision() Method Details
- Signature:
Properties inSubdivision(final String... subdivisions)
- Usage: Chain after any holiday assertion method
- Nested subdivisions: For cities within states, include both codes (e.g.,
inSubdivision("by", "mu") for Munich in Bavaria)
- Valid in subdivision: The method checks that a holiday is present in the specified subdivision
Example from HolidayDETest.java
@Test
void ensuresAllHolidaysFor2024() {
assertFor(GERMANY)
.hasFixedHoliday("NEW_YEAR", JANUARY, 1).and()
.hasFixedHoliday("LABOUR_DAY", MAY, 1).and()
.hasFixedHoliday("CHRISTMAS", DECEMBER, 25).and()
.hasFixedHoliday("EPIPHANY", JANUARY, 6).inSubdivision("bw").and()
.hasFixedHoliday("ALL_SAINTS", NOVEMBER, 1).inSubdivision("bw").and()
.hasChristianHoliday("CORPUS_CHRISTI").inSubdivision("bw").and()
.hasFixedHoliday("EPIPHANY", JANUARY, 6).inSubdivision("by").and()
.hasFixedHoliday("ALL_SAINTS", NOVEMBER, 1).inSubdivision("by").and()
.hasChristianHoliday("CORPUS_CHRISTI").inSubdivision("by").and()
.hasFixedHoliday("ASSUMPTION_DAY", AUGUST, 15).inSubdivision("by", "mu")
.check();
}
Best Practices
- Use ISO codes: Always use official ISO 3166-2 subdivision codes
- Clear descriptions: Include the full subdivision name in the
description attribute
- Document sources: Add
<Sources> elements for subdivision holiday references
- Nested when appropriate: Use nested SubConfigurations for e.g. cities within states
- Consistent ordering: Place SubConfigurations after the main
<Holidays> section
- Validity periods: Use
validFrom/validTo for historical accuracy
Common Subdivision Examples
United States (California)
<SubConfigurations hierarchy="CA" description="California">
<Holidays>
<Fixed month="JANUARY" day="1" descriptionPropertiesKey="NEW_YEAR"/>
<FixedWeekday which="THIRD" weekday="MONDAY" month="JANUARY" descriptionPropertiesKey="MLK_DAY"/>
</Holidays>
</SubConfigurations>
Germany (Bavaria)
<SubConfigurations hierarchy="by" description="Bavaria">
<Holidays>
<Fixed month="JANUARY" day="6" descriptionPropertiesKey="EPIPHANY"/>
<Fixed month="NOVEMBER" day="1" descriptionPropertiesKey="ALL_SAINTS"/>
<ChristianHoliday type="CORPUS_CHRISTI"/>
</Holidays>
</SubConfigurations>
France (Corsica)
<SubConfigurations hierarchy="2C" description="Corsica">
<Holidays>
<Fixed month="MAY" day="15" descriptionPropertiesKey="CORSICA_LIBERATION"/>
</Holidays>
</SubConfigurations>
ISO 3166-2 Reference
| Country | ISO Code | Subdivision Codes |
|---|
| Germany | DE | be, bb, bw, by, hb, he, hh, mv, ni, nw, rp, sl, sn, st, sh, th |
| United States | US | CA, NY, TX, FL, ... (state codes) |
| France | FR | 01, 02, ... (department codes) |
| Austria | AT | WI, B, K, ... (state codes) |
Sources: https://en.wikipedia.org/wiki/ISO_3166-2