"""Zeitfunktionen. Fachlich gilt durchgängig `Europe/Berlin`.""" from datetime import UTC, date, datetime, timedelta from zoneinfo import ZoneInfo from app.core.config import settings def tz() -> ZoneInfo: return ZoneInfo(settings.timezone) def now() -> datetime: """Aktueller Zeitpunkt in der fachlichen Zeitzone.""" return datetime.now(tz()) def utcnow() -> datetime: """Aktueller Zeitpunkt in UTC – für Zeitstempel in der Datenbank.""" return datetime.now(UTC) def today() -> date: """Heutiges Datum in der fachlichen Zeitzone.""" return now().date() def month_start(day: date) -> date: """Erster Tag des Monats, in dem `day` liegt.""" return day.replace(day=1) def month_end(day: date) -> date: """Letzter Tag des Monats, in dem `day` liegt.""" if day.month == 12: return day.replace(day=31) return day.replace(month=day.month + 1, day=1) - timedelta(days=1) def add_months(day: date, months: int) -> date: """Verschiebt ein Datum um ganze Monate; der Monatserste bleibt Monatserster.""" total = day.month - 1 + months year = day.year + total // 12 month = total % 12 + 1 last_day = month_end(date(year, month, 1)).day return date(year, month, min(day.day, last_day))