from functools import lru_cache import arrow from enum import IntEnum class Weekday(IntEnum): """Enumeration for days of the week.""" Monday = 0 Tuesday = 1 Wednesday = 2 Thursday = 3 Friday = 4 Saturday = 5 Sunday = 6 @lru_cache(maxsize=100) def am_i_inside_time( day_of_week: str, time_str: str, timezone_str: str, duration: int = 15, ) -> bool: """ Determines if the current time falls within a specified time range. Parameters: day_of_week (str): The day of the week (e.g., 'Monday'). time_str (str): The start time in 'HH:MM' format. timezone_str (str): The timezone identifier (e.g., 'Europe/Berlin'). duration (int, optional): The duration of the time range in minutes. Default is 15. Returns: bool: True if the current time is within the time range, False otherwise. """ # Parse the target day of the week try: target_weekday = Weekday[day_of_week.capitalize()] except KeyError: raise ValueError(f"Invalid day_of_week: '{day_of_week}'. Must be a valid weekday name.") # Parse the start time try: hour, minute = map(int, time_str.split(':')) if not (0 <= hour <= 23 and 0 <= minute <= 59): raise ValueError except (ValueError, AttributeError): raise ValueError(f"Invalid time_str: '{time_str}'. Must be in 'HH:MM' format.") # Get the current time in the specified timezone try: now_tz = arrow.now(timezone_str.strip()) except Exception as e: raise ValueError(f"Invalid timezone_str: '{timezone_str}'. Must be a valid timezone identifier.") # Check if the current day matches the target day or overlaps due to duration current_weekday = now_tz.weekday() # Create start datetime for today in target timezone start_datetime_tz = now_tz.replace(hour=hour, minute=minute, second=0, microsecond=0) # Handle previous day's overlap if target_weekday == (current_weekday - 1) % 7: # Calculate start and end times for the overlap from the previous day start_datetime_tz = start_datetime_tz.shift(days=-1) end_datetime_tz = start_datetime_tz.shift(minutes=duration) if start_datetime_tz <= now_tz < end_datetime_tz: return True # Handle current day's range if target_weekday == current_weekday: end_datetime_tz = start_datetime_tz.shift(minutes=duration) if start_datetime_tz <= now_tz < end_datetime_tz: return True # Handle next day's overlap if target_weekday == (current_weekday + 1) % 7: end_datetime_tz = start_datetime_tz.shift(minutes=duration) if now_tz < start_datetime_tz and now_tz.shift(days=1) < end_datetime_tz: return True return False def is_within_schedule(time_schedule_limit, default_tz="UTC"): """ Check if the current time is within a scheduled time window. Parameters: time_schedule_limit (dict): Schedule configuration with timezone, day settings, etc. default_tz (str): Default timezone to use if not specified. Default is 'UTC'. Returns: bool: True if current time is within the schedule, False otherwise. """ if time_schedule_limit and time_schedule_limit.get('enabled'): # Get the timezone the time schedule is in, so we know what day it is there tz_name = time_schedule_limit.get('timezone') if not tz_name: tz_name = default_tz # Get current day name in the target timezone now_day_name_in_tz = arrow.now(tz_name.strip()).format('dddd') selected_day_schedule = time_schedule_limit.get(now_day_name_in_tz.lower()) if not selected_day_schedule.get('enabled'): return False duration = selected_day_schedule.get('duration') selected_day_run_duration_m = int(duration.get('hours')) * 60 + int(duration.get('minutes')) is_valid = am_i_inside_time(day_of_week=now_day_name_in_tz, time_str=selected_day_schedule['start_time'], timezone_str=tz_name, duration=selected_day_run_duration_m) return is_valid return False