"""Date and ISO helpers for duty ranges and API validation.""" import re from datetime import date, datetime, timezone def day_start_iso(d: date) -> str: """ISO 8601 start of calendar day UTC: YYYY-MM-DDT00:00:00Z.""" return d.isoformat() + "T00:00:00Z" def day_end_iso(d: date) -> str: """ISO 8601 end of calendar day UTC: YYYY-MM-DDT23:59:59Z.""" return d.isoformat() + "T23:59:59Z" def duty_to_iso(d: date, hour_utc: int, minute_utc: int) -> str: """ISO 8601 with Z for start of duty on date d at given UTC time.""" dt = datetime(d.year, d.month, d.day, hour_utc, minute_utc, 0, tzinfo=timezone.utc) return dt.strftime("%Y-%m-%dT%H:%M:%SZ") _ISO_DATE_RE = re.compile(r"^\d{4}-\d{2}-\d{2}$") def parse_iso_date(s: str) -> date | None: """Parse YYYY-MM-DD string to date. Returns None if invalid.""" if not s or not _ISO_DATE_RE.match(s.strip()): return None try: return date.fromisoformat(s.strip()) except ValueError: return None def validate_date_range(from_date: str, to_date: str) -> None: """Validate from_date and to_date are YYYY-MM-DD and from_date <= to_date. Raises ValueError if invalid.""" if not _ISO_DATE_RE.match(from_date or "") or not _ISO_DATE_RE.match(to_date or ""): raise ValueError("Параметры from и to должны быть в формате YYYY-MM-DD") if from_date > to_date: raise ValueError("Дата from не должна быть позже to")