Intervals: a span between two ends, 2026-06-01/2026-06-30.
An interval is the {:span, from, to} form of a %Tempo{}. Each end is a
value, or one of the two is a duration (2026-06-01/P1M), or an end is
open (2026-06-01/..). Both ends are in one calendar and one zone (law 5).
A date end is the date the interval runs through, and a clock end is the reading it runs to, as the text is read (law 9); the span the interval denotes is half-open either way.
new/1 builds one from its two ends, and from/1, to/1 and
endpoints/1 read them back. instants/1 gives the instants it begins
and ends at, and leap_seconds_spanned/1 and spans_leap_second?/1
the leap seconds within it.
Summary
Functions
Both ends of an interval.
The start of an interval.
The instants an interval runs between: the one it begins at and the one
it ends at, the end not in it. An end written to a date is read through
(law 9), so 2026-06-15/2026-06-20 ends as the 21st begins. It is what a
store of instants, a database's range of timestamps, holds of an
interval.
The leap seconds an interval spans, each as the UTC date it ends:
Tempo.LeapSeconds.spanned/1, returning the list or the error.
Builds an interval from its ends.
Builds an interval from its two ends, as new/1 does.
Builds an interval as new/1 does, returning it or raising.
Whether an interval spans a leap second, so that its length in elapsed seconds is not its length on the clock.
The end of an interval, as written: a date end is the date the interval runs through.
Types
@type endpoint() :: Tempo.t() | Tempo.Duration.t() | :open
Functions
Both ends of an interval.
Arguments
intervalis aTempo.t/0interval.
Returns
{from, to}, each as written. An expression that is no interval raises aTempo.ConversionError.
Examples
iex> Tempo.Interval.endpoints(~o"2026-06-01/P1M")
{~o"2026-06-01", ~o"P1M"}
The start of an interval.
Arguments
intervalis aTempo.t/0interval.
Returns
- The start as written: a value, a duration or
:open. An expression that is no interval raises aTempo.ConversionError.
Examples
iex> Tempo.Interval.from(~o"2026-06-01/2026-06-30")
~o"2026-06-01"
iex> Tempo.Interval.from(~o"P1M/2026-06-30")
~o"P1M"
@spec instants(Tempo.t()) :: {:ok, {NaiveDateTime.t() | DateTime.t() | nil, NaiveDateTime.t() | DateTime.t() | nil}} | {:error, Exception.t()}
The instants an interval runs between: the one it begins at and the one
it ends at, the end not in it. An end written to a date is read through
(law 9), so 2026-06-15/2026-06-20 ends as the 21st begins. It is what a
store of instants, a database's range of timestamps, holds of an
interval.
Arguments
intervalis aTempo.t/0interval with a year.
Returns
{:ok, {from, to}}, each aNaiveDateTimefor an interval with no zone, aDateTimefor one in a zone or at a shift, ornilfor an open end, so{nil, nil}for../... The date-times are of the interval's calendar.{:error, exception}for an interval with no year, as forTempo.to_interval/2.
Examples
iex> Tempo.Interval.instants(~o"2026-06-15/2026-06-20")
{:ok, {~N[2026-06-15 00:00:00], ~N[2026-06-21 00:00:00]}}
iex> Tempo.Interval.instants(~o"2026-06-15T09:00Z/2026-06-15T17:00Z")
{:ok, {~U[2026-06-15 09:00:00Z], ~U[2026-06-15 17:00:00Z]}}
iex> Tempo.Interval.instants(~o"2026-06-15/..")
{:ok, {~N[2026-06-15 00:00:00], nil}}
@spec leap_seconds_spanned(Tempo.t()) :: [Tempo.LeapSeconds.date()] | {:error, Exception.t()}
The leap seconds an interval spans, each as the UTC date it ends:
Tempo.LeapSeconds.spanned/1, returning the list or the error.
Arguments
intervalis aTempo.t/0with a year and both its ends.
Returns
A list of
{year, month, day}, empty when it spans none.{:error, %Tempo.ConversionError{}}for an interval with no year or with an open end.
Examples
iex> Tempo.Interval.leap_seconds_spanned(~o"2015-01-01/2017-12-31")
[{2015, 6, 30}, {2016, 12, 31}]
@spec new(keyword()) :: {:ok, Tempo.t()} | {:error, Exception.t()}
Builds an interval from its ends.
Arguments
optionsis a keyword list with the two ends.
Options
:fromis the start: a value, a duration (when:tois a value), or:open.:tois the end: a value, a duration (when:fromis a value), or:open. A date end is the date the interval runs through.:metadatais a map the caller keeps on the interval. The default is%{}.
Returns
{:ok, interval}, aTempo.t/0of the:spanform.{:error, %Tempo.IntervalEndpointsError{}}when the ends are in two calendars or two zones, are both durations, both open, or out of order, or when an end is no value, duration or:open(an interval or a set is not an end).
Examples
iex> Tempo.Interval.new(from: ~o"2026-06-01", to: ~o"2026-06-30")
{:ok, ~o"2026-06-01/2026-06-30"}
iex> Tempo.Interval.new(from: ~o"2026-06-01", to: ~o"P1M")
{:ok, ~o"2026-06-01/P1M"}
iex> Tempo.Interval.new(from: ~o"2026-06-01", to: :open)
{:ok, ~o"2026-06-01/.."}
iex> {:error, %Tempo.IntervalEndpointsError{reason: :order}} =
...> Tempo.Interval.new(from: ~o"2026-06-30", to: ~o"2026-06-01")
iex> {:error, %Tempo.IntervalEndpointsError{reason: :calendars}} =
...> Tempo.Interval.new(from: ~o"2026-06-01", to: ~o"5786-03-15[u-ca=hebrew]")
@spec new(endpoint(), endpoint(), map()) :: {:ok, Tempo.t()} | {:error, Exception.t()}
Builds an interval from its two ends, as new/1 does.
Arguments
fromis the start: a value, a duration (whentois a value), or:open.tois the end: a value, a duration (whenfromis a value), or:open.metadatais a map the caller keeps on the interval. The default is%{}.
Returns
{:ok, interval}or{:error, exception}, asnew/1returns.
Examples
iex> Tempo.Interval.new(~o"2026-06-15T09", ~o"2026-06-15T17")
{:ok, ~o"2026-06-15T09/2026-06-15T17"}
Builds an interval as new/1 does, returning it or raising.
Arguments
optionsis a keyword list with the two ends, as fornew/1.
Options
- The options of
new/1.
Returns
Examples
iex> Tempo.Interval.new!(from: ~o"2026", to: ~o"2028")
~o"2026/2028"
Whether an interval spans a leap second, so that its length in elapsed seconds is not its length on the clock.
Arguments
intervalis aTempo.t/0with a year and both its ends.
Returns
trueorfalse; raises aTempo.ConversionErrorfor an interval with no year or with an open end.
Examples
iex> Tempo.Interval.spans_leap_second?(~o"2016-12-31T23:00:00Z/2017-01-01T01:00:00Z")
true
iex> Tempo.Interval.spans_leap_second?(~o"2026-06-15/2026-06-16")
false
The end of an interval, as written: a date end is the date the interval runs through.
Arguments
intervalis aTempo.t/0interval.
Returns
- The end as written: a value, a duration or
:open. An expression that is no interval raises aTempo.ConversionError.
Examples
iex> Tempo.Interval.to(~o"2026-06-01/2026-06-30")
~o"2026-06-30"
iex> Tempo.Interval.to(~o"2026-06-01/..")
:open