Clock is a platform primitive that abstracts time access. Instead of calling datetime.now() directly, components inject a Clock port, enabling deterministic testing and consistent time zone handling. Implementations include SystemClock for production and FixedClock for testing.

0
Ports
0
Schemas
3
Hooks
2
Events
01

Ports

Required

No required ports

Optional
  • EventBus optional
    Publish time events (FixedClock, test observability)
Adapters Provided
  • SystemClock
    implements Clock
    Production clock using system time
  • FixedClock
    implements Clock
    Test clock with controllable time
02

Schemas

Defines

No schemas defined

Uses

No external schemas used

03

Hooks

  • before_now
    Before returning current time from now()
    outputs: Patch
  • after_advance
    After FixedClock.advance() modifies time (testing only)
    outputs: SideEffectRequest
  • after_set
    After FixedClock.set() changes time (testing only)
    outputs: SideEffectRequest
04

Events

  • TimeAdvanced v1
    After FixedClock.advance() is called (testing only)
    payload: {clock_id, before, after, delta}
  • TimeSet v1
    After FixedClock.set() is called (testing only)
    payload: {clock_id, before, after}
05

Stories

06

Examples

Inject Clock into a use case
class CreateTaskUseCase:
    def __init__(self, repo: TaskRepository, clock: Clock) -> None:
        self._repo = repo
        self._clock = clock

    async def execute(self, input: CreateTaskInput) -> CreateTaskOutput:
        now = self._clock.now()
        task = Task(id=uuid4(), created_at=now, ...)
        await self._repo.add(task)
        return CreateTaskOutput(task_id=task.id, created_at=now)

Use cases receive Clock as a dependency.

Test with FixedClock
from datetime import datetime, UTC
from psp.platform.clock import FixedClock

def test_task_created_at():
    fixed_time = datetime(2024, 1, 15, 10, 30, tzinfo=UTC)
    clock = FixedClock(fixed_time)

    use_case = CreateTaskUseCase(repo=InMemoryRepo(), clock=clock)
    result = use_case.execute(CreateTaskInput(title="Test"))

    assert result.created_at == fixed_time

Control time in tests for deterministic results.

Advance time in tests
clock = FixedClock(datetime(2024, 1, 1, tzinfo=UTC))

# Create a reminder due in 1 hour
reminder = scheduler.schedule(due_at=clock.now() + timedelta(hours=1))

# Advance time by 2 hours
clock.advance(hours=2)

# Now the reminder is overdue
assert reminder.due_at < clock.now()

Simulate time passing for expiration tests.

API Reference

This component mounts routes under /v1/clock. View OpenAPI specification