Files
org-parking/services/holidays.py
Stefano Manfredi c74a0ed350 Initial commit: Parking Manager
Features:
- Manager-centric parking spot management
- Fair assignment algorithm (parking/presence ratio)
- Presence tracking calendar
- Closing days (specific & weekly recurring)
- Guarantees and exclusions
- Authelia/LLDAP integration for SSO

Stack:
- FastAPI backend
- SQLite database
- Vanilla JS frontend
- Docker deployment
2025-11-26 23:37:50 +00:00

117 lines
3.0 KiB
Python

"""
Holiday Service
Configurable holiday calculation for different regions
Currently supports Italian holidays. Can be extended to support other regions
by adding new holiday sets and a configuration option.
"""
from datetime import datetime, date, timedelta
def calculate_easter(year: int) -> date:
"""Calculate Easter Sunday using the Computus algorithm"""
a = year % 19
b = year // 100
c = year % 100
d = b // 4
e = b % 4
f = (b + 8) // 25
g = (b - f + 1) // 3
h = (19 * a + b - d - g + 15) % 30
i = c // 4
k = c % 4
l = (32 + 2 * e + 2 * i - h - k) % 7
m = (a + 11 * h + 22 * l) // 451
month = (h + l - 7 * m + 114) // 31
day = ((h + l - 7 * m + 114) % 31) + 1
return date(year, month, day)
def get_easter_monday(year: int) -> date:
"""Get Easter Monday for a given year"""
easter = calculate_easter(year)
return easter + timedelta(days=1)
# Italian fixed holidays (month, day)
ITALIAN_FIXED_HOLIDAYS = [
(1, 1), # New Year's Day
(1, 6), # Epiphany
(4, 25), # Liberation Day
(5, 1), # Labour Day
(6, 2), # Republic Day
(8, 15), # Assumption
(11, 1), # All Saints
(12, 8), # Immaculate Conception
(12, 25), # Christmas
(12, 26), # St. Stephen's
]
def is_italian_holiday(check_date: date | datetime) -> bool:
"""Check if a date is an Italian public holiday"""
if isinstance(check_date, datetime):
check_date = check_date.date()
year = check_date.year
month = check_date.month
day = check_date.day
# Check fixed holidays
if (month, day) in ITALIAN_FIXED_HOLIDAYS:
return True
# Check Easter Monday
easter_monday = get_easter_monday(year)
if check_date == easter_monday:
return True
return False
def get_holidays_for_year(year: int) -> list[dict]:
"""
Get all holidays for a given year.
Returns list of {date: YYYY-MM-DD, name: string}
"""
holidays = []
# Fixed holidays
holiday_names = [
"New Year's Day", "Epiphany", "Liberation Day", "Labour Day",
"Republic Day", "Assumption", "All Saints", "Immaculate Conception",
"Christmas", "St. Stephen's Day"
]
for (month, day), name in zip(ITALIAN_FIXED_HOLIDAYS, holiday_names):
holidays.append({
"date": f"{year}-{month:02d}-{day:02d}",
"name": name
})
# Easter Monday
easter_monday = get_easter_monday(year)
holidays.append({
"date": easter_monday.strftime("%Y-%m-%d"),
"name": "Easter Monday"
})
# Sort by date
holidays.sort(key=lambda h: h["date"])
return holidays
def is_holiday(check_date: date | datetime | str, region: str = "IT") -> bool:
"""
Check if a date is a holiday for the given region.
Currently only supports IT (Italy).
"""
if isinstance(check_date, str):
check_date = datetime.strptime(check_date, "%Y-%m-%d").date()
if region == "IT":
return is_italian_holiday(check_date)
# Default: no holidays
return False