39 lines
1,010 B
Python
39 lines
1,010 B
Python
"""Injectable clock abstraction for testability."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from datetime import UTC, datetime, timedelta
|
|
from typing import Protocol
|
|
|
|
|
|
class Clock(Protocol):
|
|
"""Clock protocol — provides current UTC time."""
|
|
|
|
def now(self) -> datetime: ...
|
|
|
|
|
|
class SystemClock:
|
|
"""Real wall-clock implementation."""
|
|
|
|
def now(self) -> datetime:
|
|
"""Return the current UTC time."""
|
|
return datetime.now(UTC)
|
|
|
|
|
|
class FakeClock:
|
|
"""Deterministic clock for tests."""
|
|
|
|
def __init__(self, start: datetime | None = None) -> None:
|
|
self._now = start or datetime(2026, 1, 1, tzinfo=UTC)
|
|
|
|
def now(self) -> datetime:
|
|
"""Return the fixed current time."""
|
|
return self._now
|
|
|
|
def advance(self, seconds: float) -> None:
|
|
"""Advance the clock by the given number of seconds."""
|
|
self._now += timedelta(seconds=seconds)
|
|
|
|
def set(self, dt: datetime) -> None:
|
|
"""Set the clock to an exact time."""
|
|
self._now = dt
|