28 lines
1.0 KiB
Python
28 lines
1.0 KiB
Python
from __future__ import annotations
|
|
from datetime import time, date, datetime, timedelta
|
|
from typing import Tuple
|
|
from zoneinfo import ZoneInfo
|
|
|
|
WARSAW_TZ = ZoneInfo("Europe/Warsaw")
|
|
UTC = ZoneInfo("UTC")
|
|
TimeRange = Tuple[time, time]
|
|
|
|
def in_range_local(t_local: time, rng: TimeRange) -> bool:
|
|
"""[start, end) in local time, supports ranges crossing midnight."""
|
|
start, end = rng
|
|
if start <= end:
|
|
return start <= t_local < end
|
|
return (t_local >= start) or (t_local < end)
|
|
|
|
def local_midnight(d: date, tz: ZoneInfo) -> datetime:
|
|
"""Return local midnight (tz-aware) for a given calendar date."""
|
|
return datetime(d.year, d.month, d.day, 0, 0, tzinfo=tz)
|
|
|
|
def end_of_business_day_utc(business_day: date, tz: ZoneInfo) -> datetime:
|
|
"""
|
|
End of the business day [start, end) expressed in UTC.
|
|
For day D this is local midnight of D+1 converted to UTC.
|
|
Correct across 23h/25h DST days.
|
|
"""
|
|
end_local = local_midnight(business_day + timedelta(days=1), tz=tz)
|
|
return end_local.astimezone(UTC) |