Tempo.Clock behaviour (Tempo v0.5.0)

Copy Markdown View Source

A behaviour for providing the current time to Tempo.

All "now" queries in Tempo (Tempo.utc_now/0, Tempo.now/1, Tempo.utc_today/0, Tempo.today/1) go through the clock configured under :ex_tempo, :clock. The default is Tempo.Clock.System, which delegates to DateTime.utc_now/0.

The indirection exists so tests can swap in a deterministic clock without stubbing the Erlang system time. Tempo.Clock.Test is a process-local stub suitable for ExUnit tests; see its module doc for the usage pattern.

Configuring the clock

Application-wide default in config/test.exs:

config :ex_tempo, clock: Tempo.Clock.Test

Process-local override (safer in async: true ExUnit suites — swaps the clock for the calling process only, leaving concurrent tests and doctests with the default clock):

Process.put({Tempo.Clock, :clock}, Tempo.Clock.Test)

In application code, use Tempo.utc_now/0 etc. rather than calling the clock directly — the swap is transparent to callers.

Implementing a custom clock

A custom clock must return a DateTime.t/0. Implementations are free to read from a database, a time-service mock, or a distributed-system clock skew model. The one rule: the returned DateTime must be in UTC (i.e. time_zone: "Etc/UTC", zero offset). Zone projection happens downstream in Tempo.now/1.

Summary

Callbacks

Return the current UTC time as a DateTime.t/0 in Etc/UTC.

Functions

Return the currently configured clock module.

Return the current UTC time from the configured clock.

Callbacks

utc_now()

@callback utc_now() :: DateTime.t()

Return the current UTC time as a DateTime.t/0 in Etc/UTC.

Functions

clock()

@spec clock() :: module()

Return the currently configured clock module.

Looks first at Process.get({Tempo.Clock, :clock}) (the process-local override used by ExUnit setups), then falls back to Application.get_env(:ex_tempo, :clock), defaulting to Tempo.Clock.System when neither is set.

The process-local override means tests that install Tempo.Clock.Test do not leak that choice into unrelated concurrent processes — a non-test doctest sharing the VM continues to see the default system clock.

utc_now()

@spec utc_now() :: DateTime.t()

Return the current UTC time from the configured clock.

Delegates to the module configured under :ex_tempo, :clock, defaulting to Tempo.Clock.System.