Ermitteln von Feiertagen

Feiertage werden nicht nach dem Zufallsprinzip gesetzt, sondern es gibt eine feste Formel anhand welcher man sämtliche Feiertage berechnen kann. Hierbei muss man zwischen festen Feiertagen wie Neujahr und dem Tag der deutschen Einheit und den flexiblen unterscheiden. Zum Beispiel die, die sich an Ostersonntag ausrichten, welcher wiederrum errechnet werden kann. Dies ist mit der Gaußschen Osterformel möglich. Wenn man dies getan hat, werden von dem Ergebnisdatum aus nur noch Additionen sowie Subtraktionen durchgeführt. So lassen sich alle beweglichen Feiertage ermitteln. Wir nutzen zum errechnen vom Ostersonntag jedoch folgende Formel:

//year ist das aktuelle Jahr
int c = year / 100;
int n = year - 19 * (year / 19);
int k = (c - 17) / 25;
int i = c - c / 4 - ((c - k) / 3) + 19 * n + 15;
i = i - 30 * (i / 30);
i = i - (i / 28) * ((1 - (i / 28)) * (29 / (i + 1)) * ((21 - n) / 11));
int j = year + (year / 4) + i + 2 - c + (c / 4);
j = j - 7 * (j / 7);
int l = i - j;

int easterMonth = 3 + ((l + 40) / 44);
int easterDay = l + 28 - 31 * (easterMonth / 4);

Anhand der Formel könnte eine Implementierung in C# zum Beispiel wie folgt aussehen:

public class HolidayDays
{
    private readonly List<Holiday> _holidays = new List<Holiday>();

    public HolidayDays()
    {
        Initialize();
    }

    public string GetHoliday(DateTime date, State state)
    {
        foreach (Holiday holiday in _holidays)
        {
            if (date.ToShortDateString().Equals(holiday.GetDate(GetEasterSunday(date.Year)).ToShortDateString()))
            {
                if (holiday.States.Any(entry => state == entry))
                    return holiday.HolidayName;
            }
        }

        return string.Empty;
    }

    public bool IsHoliday(DateTime date, State state)
    {
        return (GetHoliday(date, state).Length > 0);
    }

    private void Initialize()
    {
        State[] all = { State.BadenWürtenberg, State.Bayern, State.Berlin, State.Brandenburg, State.Bremen, State.Hamburg, State.Hessen, State.MecklenburgVorpommern, State.Niedersachsen, State.NordrheinWestfalen, State.RheinlandPfalz, State.Saarland, State.Sachsen, State.SachsenAnhalt, State.SchleswigHolstein, State.Thüringen };

        _holidays.Add(new Holiday("Neujahr", "01.01", all));
        _holidays.Add(new Holiday("Heiligen Drei Könige", "06.01", new[] { State.BadenWürtenberg, State.Bayern, State.SachsenAnhalt }));
        _holidays.Add(new Holiday("Karfreitag", -2, all));
        _holidays.Add(new Holiday("Ostersonntag", 0, all));
        _holidays.Add(new Holiday("Ostermontag", 1, all));
        _holidays.Add(new Holiday("Tag der Arbeit", "01.05", all));
        _holidays.Add(new Holiday("Christi Himmelfahrt", 39, all));
        _holidays.Add(new Holiday("Pfingstsonntag", 49, all));
        _holidays.Add(new Holiday("Pfingstmontag", 50, all));
        _holidays.Add(new Holiday("Fronleichnam", 60, new[] { State.BadenWürtenberg, State.Bayern, State.Hessen, State.NordrheinWestfalen, State.RheinlandPfalz, State.Saarland }));
        _holidays.Add(new Holiday("Maria Himmelfahrt", "15.08", new[] { State.Saarland }));
        _holidays.Add(new Holiday("Tag der dt. Einheit", "03.10", all));
        _holidays.Add(new Holiday("Allerheiligen", "01.11", new[] { State.BadenWürtenberg, State.Bayern, State.NordrheinWestfalen, State.RheinlandPfalz, State.Saarland }));
        _holidays.Add(new Holiday("1. Weinachtstag", "25.12", all));
        _holidays.Add(new Holiday("2. Weinachtstag", "26.12", all));
    }

    private static DateTime GetEasterSunday(int year)
    {
        int c = year / 100;
        int n = year - 19 * (year / 19);
        int k = (c - 17) / 25;
        int i = c - c / 4 - ((c - k) / 3) + 19 * n + 15;
        i = i - 30 * (i / 30);
        i = i - (i / 28) * ((1 - (i / 28)) * (29 / (i + 1)) * ((21 - n) / 11));
        int j = year + (year / 4) + i + 2 - c + (c / 4);
        j = j - 7 * (j / 7);
        int l = i - j;

        int easterMonth = 3 + ((l + 40) / 44);
        int easterDay = l + 28 - 31 * (easterMonth / 4);

        return Convert.ToDateTime(string.Format("{0}.{1}.{2}", easterDay, easterMonth, year));
    }
}

internal class Holiday
{
    private readonly HolidayKind _holidayKind;
    private readonly int _addDays;
    private readonly string _fixedDate;

    public String HolidayName { get; private set; }
    public DateTime Date { get; private set; }
    public State[] States { get; private set; }

    internal Holiday(string holidayName, string fixedDate, State[] states)
    {
        _addDays = 0;
        _holidayKind = HolidayKind.Fixed;
        _fixedDate = fixedDate;

        HolidayName = holidayName;
        States = states;
    }

    internal Holiday(String holidayName, int addDays, State[] states)
    {
        _addDays = addDays;
        _holidayKind = HolidayKind.Dynamic;

        HolidayName = holidayName;
        States = states;
    }

    public DateTime GetDate(DateTime easterSunday)
    {
        Date = _holidayKind != HolidayKind.Fixed ? easterSunday.AddDays(_addDays) : DateTime.Parse(_fixedDate + "." + easterSunday.Year);
        return DateTime.Parse(string.Format("{0:dd.MM.yyyy}", Date));
    }
}

public enum State
{
    BadenWürtenberg,
    Bayern,
    Berlin,
    Brandenburg,
    Bremen,
    Hamburg,
    Hessen,
    MecklenburgVorpommern,
    Niedersachsen,
    NordrheinWestfalen,
    RheinlandPfalz,
    Saarland,
    Sachsen,
    SachsenAnhalt,
    SchleswigHolstein,
    Thüringen
}

public enum HolidayKind
{
    Fixed,
    Dynamic
}

Hier können wir die Klasse „HolidayDays“ mittels „GetHoliday“ oder „IsHoliday“ prüfen lassen, ob ein bestimmter Tag ein Feiertag ist bzw. welcher Feiertag auf diesen Tag fällt. Die einzelnen deutschen Feiertage sind hierbei je nach Bundesstaat durch die Methode „Initialize“ erzeugt worden.