from typing import Literal, TypedDict, List DayPattern = Literal[ "daily", "weekdays", "weekend", "mon_wed_fri", "tue_thu", "mon_thu", "sat", "sun", "monthly", ] class Routine(TypedDict): routine_id: str days: str time_local: str # HH:MM class RoutineDecision(TypedDict): routine_id: str should_run: bool reason: str def _matches_day(pattern: str, weekday: int) -> bool: """weekday: 0=Monday ... 6=Sunday""" p = pattern.lower() if p == "daily": return True if p == "weekdays": return weekday < 5 if p == "weekend": return weekday >= 5 if p == "sat": return weekday == 5 if p == "sun": return weekday == 6 if p == "mon_wed_fri": return weekday in (0, 2, 4) if p == "tue_thu": return weekday in (1, 3) if p == "mon_thu": return weekday in (0, 3) if p == "monthly": return False # handled elsewhere or by calendar return False def decide_routines_to_run(routines: List[Routine], weekday: int, current_time: str) -> List[RoutineDecision]: """Decide which routines should run at a given weekday/time. - weekday: 0=Monday ... 6=Sunday - current_time: 'HH:MM' string """ decisions: List[RoutineDecision] = [] for r in routines: rid = r["routine_id"] days = r.get("days", "daily") time_local = r.get("time_local", "00:00") if not _matches_day(days, weekday): decisions.append( { "routine_id": rid, "should_run": False, "reason": f"Pattern '{days}' does not match this weekday.", } ) continue if time_local == current_time: decisions.append( { "routine_id": rid, "should_run": True, "reason": "Time and day pattern match current moment.", } ) else: decisions.append( { "routine_id": rid, "should_run": False, "reason": f"Current time {current_time} != routine time {time_local}.", } ) return decisions if __name__ == "__main__": sample = [ {"routine_id": "RT_MORNING_LR", "days": "daily", "time_local": "07:15"}, {"routine_id": "RT_LAUNDRY_REMIND", "days": "sat", "time_local": "10:00"}, ] # Example: Saturday at 07:15 -> weekday=5 for d in decide_routines_to_run(sample, weekday=5, current_time="07:15"): print(d)