Feat: Bundesland-Feiertage für Werktagsberechnung hinzugefügt

- Neue Funktion zur Abfrage bundeslandspezifischer Feiertage über feiertage-api.de
- Werktagsberechnung berücksichtigt jetzt optional Feiertage des gewählten Bundeslandes
- Frontend: Dropdown für Bundesland-Auswahl (nur aktiv wenn Werktage-Checkbox aktiviert)
- Anzeige der Anzahl Wochenendtage und Feiertage im Ergebnis
- REST API erweitert um bundesland-Parameter
- README.md aktualisiert mit Dokumentation der neuen Funktion
This commit is contained in:
2025-07-25 17:10:57 +02:00
parent 5009ec1085
commit e2a5c1a3fa
4 changed files with 114 additions and 9 deletions

38
app.py
View File

@@ -4,6 +4,7 @@ import numpy as np
from dateutil.relativedelta import relativedelta
import os
import time
import requests
app_start_time = time.time()
@@ -14,6 +15,18 @@ app.secret_key = os.environ.get('SECRET_KEY', 'dev-key')
WOCHENTAGE = ["Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag", "Sonntag"]
def get_feiertage(year, bundesland):
"""Holt die Feiertage für ein Jahr und Bundesland von feiertage-api.de."""
url = f"https://feiertage-api.de/api/?jahr={year}&nur_land={bundesland}"
try:
resp = requests.get(url, timeout=5)
data = resp.json()
# Die API gibt ein Dict mit Feiertagsnamen als Key, jeweils mit 'datum' als Wert
return [v['datum'] for v in data.values() if 'datum' in v]
except Exception as e:
print(f"Fehler beim Abrufen der Feiertage: {e}")
return []
@app.route('/', methods=['GET', 'POST'])
def index():
# Rudimentäres Logging für Page Impressions
@@ -40,6 +53,7 @@ def index():
from datetime import datetime as dt
f.write(f"{dt.now().isoformat()} PAGEVIEW\n")
tage = werktage = wochentag = datumsrechnung = werktagsrechnung = kw_berechnen = kw_datum = wochen_monate = None
feiertage_anzahl = wochenendtage_anzahl = None
active_idx = 0
plusminus_result = None
if request.method == 'POST':
@@ -53,13 +67,27 @@ def index():
start = request.form.get('start1')
end = request.form.get('end1')
is_werktage = request.form.get('werktage') in ('on', 'true', '1', True)
bundesland = request.form.get('bundesland')
try:
d1 = datetime.strptime(start, '%Y-%m-%d')
d2 = datetime.strptime(end, '%Y-%m-%d')
if d1 > d2:
d1, d2 = d2, d1
# Feiertage bestimmen
holidays = []
if bundesland:
years = set([d1.year, d2.year])
for y in years:
holidays.extend(get_feiertage(y, bundesland))
# Alle Tage im Bereich
all_days = [(d1 + timedelta(days=i)).date() for i in range((d2 - d1).days + 1)]
# Wochenendtage zählen
wochenendtage_anzahl = sum(1 for d in all_days if d.weekday() >= 5)
# Feiertage zählen (nur die, die im Bereich liegen und nicht auf Wochenende fallen)
feiertage_im_zeitraum = [f for f in holidays if d1.date() <= datetime.strptime(f, '%Y-%m-%d').date() <= d2.date()]
feiertage_anzahl = sum(1 for f in feiertage_im_zeitraum if datetime.strptime(f, '%Y-%m-%d').date().weekday() < 5)
if is_werktage:
if d1 > d2:
d1, d2 = d2, d1
tage = np.busday_count(d1.date(), (d2 + timedelta(days=1)).date())
tage = np.busday_count(d1.date(), (d2 + timedelta(days=1)).date(), holidays=holidays)
else:
tage = abs((d2 - d1).days)
except Exception:
@@ -129,7 +157,9 @@ def index():
plusminus_result = f"Datum {d.strftime('%d.%m.%Y')} {'plus' if anzahl_int>=0 else 'minus'} {abs(anzahl_int)} Monate: {result.strftime('%d.%m.%Y')}"
except Exception:
plusminus_result = 'Ungültige Eingabe'
return render_template('index.html', tage=tage, werktage=werktage, wochentag=wochentag, plusminus_result=plusminus_result, kw_berechnen=kw_berechnen, kw_datum=kw_datum, active_idx=active_idx)
return render_template('index.html', tage=tage, werktage=werktage, wochentag=wochentag, plusminus_result=plusminus_result, kw_berechnen=kw_berechnen, kw_datum=kw_datum, active_idx=active_idx
, feiertage_anzahl=feiertage_anzahl, wochenendtage_anzahl=wochenendtage_anzahl
)
def parse_log_stats(log_path):