Chronix.Duration (Chronix v0.2.0)

Copy Markdown View Source

Parses duration expressions into {unit, n} tuples suitable for DateTime.shift/2.

Supported formats:

  • "in X units" — future (e.g. "in 2 seconds")
  • "X units from now" — future
  • "X units ago" — past
  • "X units" — future (bare form)
  • "next monday" / "last friday" — resolved to a {:day, n} shift
  • "this monday" / "on friday" — upcoming including today
  • "next week" / "last month" / "next year" etc.

Units accept singular or plural forms exactly (second/seconds, etc.). Extra units: fortnight (= 14 days), quarter (= 3 months), decade (= 10 years), century (= 100 years).

Numbers may include commas ("1,000 seconds") and may be fractional ("in 1.5 hours"). Fractional durations are internally converted to a {:microsecond, n} tuple; fractional months and years are rejected because they have no unambiguous conversion.

Weekday expressions are resolved against :reference_date, which defaults to DateTime.utc_now/0.

Examples

iex> Chronix.Duration.parse("in 2 seconds")
{:ok, {:second, 2}}

iex> Chronix.Duration.parse("2 seconds ago")
{:ok, {:second, -2}}

iex> Chronix.Duration.parse("5 months from now")
{:ok, {:month, 5}}

iex> Chronix.Duration.parse("next monday", reference_date: ~U[2025-01-27 00:00:00Z])
{:ok, {:day, 7}}

iex> Chronix.Duration.parse("in 2 seconds ago")
{:error, "cannot combine 'in' and 'ago'"}

Summary

Types

duration()

@type duration() :: {unit(), integer()}

result()

@type result() :: {:ok, duration()} | {:error, String.t()}

unit()

@type unit() ::
  :second | :minute | :hour | :day | :week | :month | :year | :microsecond

Functions

parse(str, opts \\ [])

@spec parse(
  String.t(),
  keyword()
) :: result()