Skip to content

Instantly share code, notes, and snippets.

@maduck
Last active December 24, 2024 12:42
Show Gist options
  • Save maduck/e52bb3cdf0e176e3f5570eaafb456bac to your computer and use it in GitHub Desktop.
Save maduck/e52bb3cdf0e176e3f5570eaafb456bac to your computer and use it in GitHub Desktop.
#!/usr/bin/python3
# -*- coding: utf-8 -*-
""" Feiertage, die nicht auf ein Wochenende fallen → Bankfeiertage """
import calendar
import datetime
import locale
locale.setlocale(locale.LC_ALL, 'de_DE.UTF-8')
class Feiertage:
def __init__(self, jahr, sample_datum):
self.jahr = jahr
self.sample_datum = sample_datum
@staticmethod
def _oster_sonntag(jahr):
"""
Ostersonntag für den gregorianischen Kalender
"""
a = jahr % 19 # Mondparameter a
b, c = divmod(jahr, 100) # Säkularzahl c
d, e = divmod(b, 4)
f = (b + 8) / 25 # Säkulare Mondschaltung
g = (b - f + 1) / 3
h = (19 * a + b - d - g + 15) % 30
i, k = divmod(c, 4)
m = (32 + 2 * e + 2 * i - h - k) % 7
n = (a + 11 * h + 22 * m) / 451
monat, tag = divmod(int(h + m - 7 * n + 114), 31)
return datetime.date(jahr, monat, tag + 1)
def bewegliche_feiertage(self, jahr):
"""
Liste der Feiertage, die nicht auf ein Wochenende fallen müssen
"""
oster_sonntag = self._oster_sonntag(jahr)
return (
(datetime.date(jahr, 1, 1), 'Neujahr'),
(oster_sonntag + datetime.timedelta(-2), 'Karfreitag'),
(oster_sonntag + datetime.timedelta(1), 'Ostermontag'),
(oster_sonntag + datetime.timedelta(39), 'Himmelfahrt'),
(oster_sonntag + datetime.timedelta(50), 'Pfingstmontag'),
(datetime.date(jahr, 5, 1), 'Tag der Arbeit'),
(datetime.date(jahr, 10, 3), 'Tag der dt. Einheit'),
(datetime.date(jahr, 11, 11), 'St. Martin'),
(datetime.date(jahr, 12, 6), 'Nikolaus'),
(datetime.date(jahr, 12, 24), 'Weihnachten'),
(datetime.date(jahr, 12, 25), 'erster Weihnachtsfeiertag'),
(datetime.date(jahr, 12, 26), 'zweiter Weihnachtsfeiertag'),
(datetime.date(jahr, 12, 31), 'Neujahr'),
)
@staticmethod
def _wochenende(datum: datetime.date) -> bool:
""" Prüft, ob ein Datum ein Wochenende ist. """
return datum.weekday() in [5, 6]
def handelstag(self, datum):
""" Prüft, ob ein Datum ein Handelstag ist. """
if datum in [i[0] for i in self.bewegliche_feiertage(datum.year)]:
return False
if self._wochenende(datum):
return False
return True
def feiertag(self, datum):
return not self.handelstag(datum)
@staticmethod
def sommerzeit(datum: datetime.date) -> bool:
""" returns True if date is between last sunday in march and last sunday in october """
last_march = datetime.date(datum.year, 3, 31)
last_october = datetime.date(datum.year, 10, 31)
sunday = calendar.SUNDAY
delta_m = (last_march.weekday() - sunday) % 7
delta_o = (last_october.weekday() - sunday) % 7
sommerzeit_start = last_march - datetime.timedelta(days=delta_m)
sommerzeit_ende = last_october - datetime.timedelta(days=delta_o)
# print("[DEBUG] start: %s" % summertime_start.strftime('%d-%b-%Y'))
# print("[DEBUG] end: %s" % summertime_end.strftime('%d-%b-%Y'))
if (sommerzeit_start < datum) and (datum < sommerzeit_ende):
return True
return False
def pretty_output(self) -> str:
output = [f'Feiertage im Jahr {self.jahr}:']
for feiertag in self.bewegliche_feiertage(self.jahr):
output.append('\t{0[0]:%A %d. %B %Y} \t\t {0[1]}'.format(feiertag))
output.append(
f'{self.sample_datum:%A, der %d.%m.%Y}, ist {"" if self.handelstag(self.sample_datum) else "k"}ein Handelstag{" (Sommerzeit)" if self.sommerzeit(self.sample_datum) else ""}.')
return '\n'.join(output)
def __str__(self):
return self.pretty_output()
if __name__ == '__main__':
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-j', '--jahr', type=int, default=datetime.date.today().year)
parser.add_argument('-d', '--datum', type=datetime.date.fromisoformat, default=datetime.date.today())
args = parser.parse_args()
meine_feiertage = Feiertage(args.jahr, args.datum)
print(meine_feiertage)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment