Closed-form step arithmetic for interval enumeration.
Backs the Enumerable protocol implementation for
Tempo.Interval.t/0 — specifically its count/1, slice/1,
and member?/2 callbacks — with O(1) (or near-O(1))
implementations driven by the calendar's date algebra rather than
walking the interval one step at a time.
Each function takes the iteration unit and the calendar in addition to the endpoints:
count_steps/4— how manyunit-wide steps fit in[from, to).nth_step/4— then-th element fromfromatunitgranularity.on_step?/4— whetherelementfalls on aunit-step boundary anchored atfrom.
Phase 1 covers :year, :month, and :day. Sub-day units
(:hour, :minute, :second, :microsecond) are added in
subsequent phases.
Summary
Functions
Count the number of unit-wide steps in the half-open span
[from, to).
Return the Tempo at step n from from at unit granularity.
Return true when element falls on a unit-step boundary
anchored at from.
Functions
@spec count_steps(Tempo.t(), Tempo.t(), atom(), module()) :: non_neg_integer() | :not_supported
Count the number of unit-wide steps in the half-open span
[from, to).
Arguments
fromis the lower-boundTempo.t/0.tois the exclusive upper-boundTempo.t/0.unitis one of:year,:month,:day(Phase 1 scope).calendaris the shared calendar module of both endpoints.
Returns
A non-negative integer count, or
:not_supportedwhen the unit / calendar combination has no closed-form path. Callers should fall back to walking.
Examples
iex> from = Tempo.from_iso8601!("2026Y")
iex> to = Tempo.from_iso8601!("2030Y")
iex> Tempo.Interval.Steps.count_steps(from, to, :year, Calendrical.Gregorian)
4
iex> from = Tempo.from_iso8601!("2026-01")
iex> to = Tempo.from_iso8601!("2027-03")
iex> Tempo.Interval.Steps.count_steps(from, to, :month, Calendrical.Gregorian)
14
iex> from = Tempo.from_iso8601!("2026-01-01")
iex> to = Tempo.from_iso8601!("2026-02-01")
iex> Tempo.Interval.Steps.count_steps(from, to, :day, Calendrical.Gregorian)
31
@spec nth_step(Tempo.t(), non_neg_integer(), atom(), module()) :: Tempo.t() | :not_supported
Return the Tempo at step n from from at unit granularity.
Arguments
fromis the anchorTempo.t/0.nis a non-negative integer step count (0 returnsfrom).unitis one of:year,:month,:day(Phase 1 scope).calendaris the calendar module.
Returns
The Tempo at step
n, or:not_supportedfor unhandled units.
Examples
iex> from = Tempo.from_iso8601!("2026-01-01")
iex> Tempo.Interval.Steps.nth_step(from, 30, :day, Calendrical.Gregorian)
~o"2026Y1M31D"
iex> from = Tempo.from_iso8601!("2026-01")
iex> Tempo.Interval.Steps.nth_step(from, 14, :month, Calendrical.Gregorian)
~o"2027Y3M"
Return true when element falls on a unit-step boundary
anchored at from.
Arguments
elementis anyTempo.t/0.fromis the anchorTempo.t/0.unitis one of:year,:month,:day(Phase 1 scope).calendaris the calendar module.
Returns
trueifelementequalsfromadvanced by some non-negative integer number ofunitsteps,falseotherwise, or:not_supported.
Examples
iex> from = Tempo.from_iso8601!("2026-01-01")
iex> elt = Tempo.from_iso8601!("2026-01-31")
iex> Tempo.Interval.Steps.on_step?(elt, from, :day, Calendrical.Gregorian)
true