""" 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