Shared comparison primitives for Tempo values.
Set operations, enumeration, and IntervalSet construction all
need to compare two time keyword lists as start-moments on the
time line. This module is the single place that definition
lives. The comparison treats missing trailing units as their
unit minimum — so [year: 2022] (which means "start of 2022")
compares correctly against [year: 2022, month: 6] (which
means "start of June 2022") without ambiguity.
For set operations that span timezones, to_utc_seconds/1
projects a zoned %Tempo{} into gregorian-seconds-since-UTC
epoch so operands in different zones can share a total order.
The projection is computed on demand and never cached — that
policy decision was made in the implicit-to-explicit plan and
revisited in the set-operations plan.
Summary
Functions
Return :earlier, :later, or :same for two %Tempo{}
endpoints comparing by their UTC-projected start-moments.
Compare two time keyword lists as start-moments on the time line.
Project a zoned %Tempo{} to UTC gregorian seconds since
year 0 (matching Erlang's :calendar.datetime_to_gregorian_seconds/1
epoch).
The start-of-unit minimum — 1 for :month, :day, :week,
:day_of_year, :day_of_week; 0 for everything else.
Functions
Return :earlier, :later, or :same for two %Tempo{}
endpoints comparing by their UTC-projected start-moments.
When both Tempos share a zone (or both have nil zone info),
this reduces to compare_time/2 on their :time lists with a
renamed return. When zones differ, both sides are projected to
UTC via to_utc_seconds/1 for a common reference frame.
Arguments
aandbare%Tempo{}structs, typically interval endpoints.
Returns
:earlier,:later, or:same.
Compare two time keyword lists as start-moments on the time line.
Missing trailing units are filled with their unit minimum
(:month / :day / :week / :day_of_year / :day_of_week
count from 1; everything else counts from 0). Both lists must
be sorted descending-by-unit — the invariant the tokenizer and
Unit.sort/2 maintain.
Mismatched units at the same position (e.g. :week vs
:month) fall through to :eq as a conservative bailout. A
well-formed comparison has operands using the same unit
vocabulary.
Arguments
aandbare keyword lists like[year: 2022, month: 6].
Returns
:ltwhenais earlier thanb.:gtwhenais later thanb.:eqwhen they are the same start-moment, or when mismatched unit vocabularies prevent a meaningful order.
Examples
iex> Tempo.Compare.compare_time([year: 2022], [year: 2022, month: 6])
:lt
iex> Tempo.Compare.compare_time([year: 2022, month: 6, day: 15], [year: 2022, month: 6, day: 15])
:eq
iex> Tempo.Compare.compare_time([year: 2023], [year: 2022, month: 12])
:gt
Project a zoned %Tempo{} to UTC gregorian seconds since
year 0 (matching Erlang's :calendar.datetime_to_gregorian_seconds/1
epoch).
The projection is per-call, never cached. When Tzdata is
updated with new zone rules, the next call automatically uses
them. Stored IntervalSet endpoints carry wall-clock + zone as
authoritative — see plans/set-operations.md for the full
rationale on why no UTC cache exists.
Arguments
tempois a%Tempo{}with at minimum year/month/day/hour/ minute/second components. Missing components are padded with their unit minimum.
Returns
integer— gregorian seconds since year 0 in UTC.
Raises
ArgumentErrorwhen the Tempo has no:yearcomponent (non-anchored values can't be projected to a universal instant).
The start-of-unit minimum — 1 for :month, :day, :week,
:day_of_year, :day_of_week; 0 for everything else.
Exposed on Tempo.Compare and Tempo.Math as the same
definition (both modules re-export via delegation).