Kalenderspielereien mit Java (2)

Im vorherigen Beitrag wurde die Berechnung von festen und beweglichen Feiertagen in Deutschland besprochen.

Holidays.in(Locale.GERMANY).isHoliday(LocalDate.now());
Holidays.in(Locale.US).isHoliday(LocalDate.now());

Der Aufruf mit einem Länder Locale gestattet eine Unterscheidung der Feiertage nach Ländern. Leider sind viele Feiertage nicht an Landesgrenzen gebunden, sondern sind regionale Besonderheiten. So existieren neben den bundesweiten Feiertagen eine Reihe von Feiertagen, die nur in einigen Bundesländern oder sogar nur in einigen Städten gefeiert werden.

Eine einfache Lösung für das Problem ist eine weitere Holiday.in Methode, die mit Bundesland Parametern aufgerufen wird.

Holiday.in(GermanFederalState.NW).isHoliday(LocalDate.now());

Die Klasse GermanFederalState ist eine Enum Klasse, die eine Konstante für jedes Bundesland enthält.

public enum GermanFederalState implements SubDivision {
  BW("Baden-Württemberg"), 
  BY("Bayern"), 
  BE("Berlin"),
...
  @Override
  public String getIso() {
    return "DE-" + name();
  }

  @Override
  public Locale getCountry() {
    return Locale.GERMANY;
  }
}

Um nun nicht für verschiedene Länder zusätzliche Methoden zu erstellen, implementiert die Enum das Interface SubDivision. Die neu erstellte Holiday.in Methode akzeptiert als Parameter Instanzen vom Typ SubDivision, kann also nicht nur deutsche Bundesländer übergeben bekommen, sondern z.B. auch Schweizer Kantone.

public enum SwissCanton implements SubDivision {
  AG("Aargau"), 
  AR("Appenzell Ausserrhoden"), 
  AI("Appenzell Innerrhoden"),
...
  @Override
  public String getIso() {
    return "CH-" + name();
  }

  @Override
  public Locale getCountry() {
    return new Locale("de", "CH");
  }
}

Beide Enum Klassen implementieren die Methode getIso des Interface SubDivision. Diese Methoden liefert das Kürzel für die in der Iso-Norm ISO 3166-2 definierten Verwaltungseinheiten. Beispielsweise für Nordrhein-Westfalen das Kürzel DE-NW und für den Kanton Uri das Kürzel CH-UR.

Für die Benennung der Konstanten in der jeweiligen Enum Klasse wurde die jeweilige Länderkennung wegen der Redundanz fortgelassen. Für Österreich muss eine andere Lösung her, denn dort sind die Bundesländer durchnummeriert.

Eine andere Organisation hilft bei der Erweiterung für Feiertage, die nur einige Städte betreffen. Der United Nations Code for Trade and Transport Locations (UN/LOCODE) definiert eindeutige Bezeichnungen für Ortschaften. So steht „DE BER“ für Berlin, „DE BFE“ für Bielefeld und „DE BOY“ für Bad Oeynhausen.

Holiday.in(GermanLocode.BOY).isHoliday(LocalDate.now());

Das obige Beispiel prüft Feiertage für die Stadt Bad Oeynhausen. Da Bad Oeynhausen keine stadtspezifischen Feiertage hat, gelten hier die Feiertage des Bundesland NRW.

Bei GermanLocode handelt es sich, wie bei GermanFederalState, um eine Enum, die ein Interface Locode implementiert.

public enum GermanLocode implements Locode {
  BFE("Bielefeld", GermanFederalState.NW), 
  BOY("Bad Oeynhausen", GermanFederalState.NW);
...
  @Override
  public String getLocode() {
    return "DE " + name();
  }
  
  @Override
  public GermanFederalState getSubDivision() {
    return subDivision;
  }
}

Mit diesen Ergänzungen können nun Feiertage definiert und geprüft werden, die bundes- oder landesweit gelten oder nur in einzelnen Gemeinden.

Im nächsten Beitrag wird die Initialisierung der spezifischen Feiertagsklassen beschrieben und einige Optimierungen vorgestellt.