""" Core DateTime Utilities Low-level datetime operations for the bakery system. All functions use Python's built-in zoneinfo for timezone handling. """ from datetime import datetime, timezone from typing import Optional from zoneinfo import ZoneInfo from .constants import DEFAULT_TIMEZONE, ISO_FORMAT def utc_now() -> datetime: """ Get current datetime in UTC with timezone awareness. Returns: Current UTC datetime """ return datetime.now(timezone.utc) def now_in_timezone(tz: str = DEFAULT_TIMEZONE) -> datetime: """ Get current datetime in specified timezone. Args: tz: IANA timezone string (e.g., "Europe/Madrid") Returns: Current datetime in the specified timezone """ return datetime.now(ZoneInfo(tz)) def to_utc(dt: datetime) -> datetime: """ Convert datetime to UTC. Args: dt: Datetime to convert (if naive, assumes UTC) Returns: Datetime in UTC timezone """ if dt.tzinfo is None: return dt.replace(tzinfo=timezone.utc) return dt.astimezone(timezone.utc) def to_timezone(dt: datetime, tz: str) -> datetime: """ Convert datetime to specified timezone. Args: dt: Datetime to convert (if naive, assumes UTC) tz: Target IANA timezone string Returns: Datetime in target timezone """ if dt.tzinfo is None: dt = dt.replace(tzinfo=timezone.utc) return dt.astimezone(ZoneInfo(tz)) def ensure_aware(dt: datetime, default_tz: str = "UTC") -> datetime: """ Ensure a datetime is timezone-aware. Args: dt: Datetime to check default_tz: Timezone to apply if datetime is naive (default: UTC) Returns: Timezone-aware datetime """ if dt.tzinfo is None: tz = ZoneInfo(default_tz) return dt.replace(tzinfo=tz) return dt def ensure_naive(dt: datetime) -> datetime: """ Remove timezone information from a datetime. Args: dt: Datetime to process Returns: Timezone-naive datetime """ if dt.tzinfo is not None: return dt.replace(tzinfo=None) return dt def parse_iso(dt_str: str) -> datetime: """ Parse ISO format datetime string. Args: dt_str: ISO format datetime string Returns: Parsed datetime (timezone-aware if timezone info present) """ return datetime.fromisoformat(dt_str) def format_iso(dt: datetime) -> str: """ Format datetime as ISO string. Args: dt: Datetime to format Returns: ISO format string """ return dt.isoformat() def format_custom(dt: datetime, format_str: str = ISO_FORMAT) -> str: """ Format datetime with custom format string. Args: dt: Datetime to format format_str: strftime format string Returns: Formatted datetime string """ return dt.strftime(format_str) def is_aware(dt: datetime) -> bool: """ Check if datetime is timezone-aware. Args: dt: Datetime to check Returns: True if timezone-aware, False otherwise """ return dt.tzinfo is not None and dt.tzinfo.utcoffset(dt) is not None def validate_timezone(tz: str) -> bool: """ Validate if timezone string is valid. Args: tz: IANA timezone string to validate Returns: True if valid, False otherwise """ try: ZoneInfo(tz) return True except Exception: return False