Ecto.ParameterizedType for persisting an interval as a
PostgreSQL tstzrange value.
It takes any expression that is one span — an interval, or a value
(~o"2026-06") as the interval it names — and loads an interval.
Usage
schema "meetings" do
field :window, Tempo.Ecto.Interval
endand in the migration:
add :window, :tstzrange(or use Tempo.SQL.Migration.add_interval/2).
Options
:resolution— on load, truncate both endpoints to the given component and drop all sub-components. One of:year,:month,:day,:hour,:minute, or:second. Defaults to:second(no truncation). See the storage contract guide for the semantics and caveats.field :reporting_period, Tempo.Ecto.Interval, resolution: :year
Storage contract
This type refuses to store values it cannot round-trip
semantically. The dump callback returns :error for:
An expression of several spans: a recurrence, a set, or a value naming several (
~o"2026Y{6,8}M"). Store those asTempo.Ecto.IntervalSetinstead.A qualification (
:uncertain,:approximate) or a calendar other than the Gregorian, which a range of instants cannot keep.Tempo.Ecto.TempoRangekeeps both.An interval unbounded on both sides. One open end is stored as a
(,b)or[a,)range in Postgres.
Bracket normalisation on load
PostgreSQL does not canonicalise tstzrange values on
output — a column populated by another writer might hold
[a, b], (a, b), or (a, b]. The loader normalises any
non-half-open range to [lower, upper)
by shifting the offending endpoint one second (Tempo is
second-resolution so this is exact).
Summary
Functions
Builds the parameterized-type tuple for use outside a schema.
Functions
@spec cast_type(keyword()) :: Ecto.Type.t()
Builds the parameterized-type tuple for use outside a schema.
Inside a schema, field :window, Tempo.Ecto.Interval, resolution: :day
does this for you. Reach for this when calling Ecto.Type.cast/2
and friends directly.
Arguments
optionsis a keyword list of options.
Options
:resolutiontruncates both endpoints on load to the given component. One of:year,:month,:day,:hour,:minute, or:second. Defaults to:second.
Returns
- A
Ecto.ParameterizedType.opts/0tuple.
Examples
iex> Tempo.Ecto.Interval.cast_type()
{:parameterized, {Tempo.Ecto.Interval, %{resolution: :second}}}
iex> Tempo.Ecto.Interval.cast_type(resolution: :year)
{:parameterized, {Tempo.Ecto.Interval, %{resolution: :year}}}