169 lines
3.4 KiB
Python
169 lines
3.4 KiB
Python
"""
|
|
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
|