Taskweft.Iso8601Duration (taskweft v0.4.0-dev.4)

Copy Markdown View Source

ISO 8601 duration parser, faithful Elixir port of lean/Planner/Iso8601Duration.lean.

Conforms to ISO 8601-1:2019 §5.5.2.4: canonical order Y → Mo → D → T → H → Mi → S (each unit at most once), fractions allowed on at most one unit and only if no smaller unit follows, weeks must stand alone. UTC-elapsed normalisation (Y = 365d, Mo = 30d, W = 7d, D = 86_400 s); civil time is out of scope.

Originally written so the Lean spec could be exercised with PropCheck against the Timex oracle and a strict spec recogniser (still is — see test/taskweft/iso8601_duration_prop_test.exs); promoted from test/support into lib so Taskweft.JSONLD.Loader.validate/2 can reject a malformed action duration at load time instead of letting it reach the NIF. The C++ NIF port lives upstream in taskweft-nif/standalone/tw_temporal.hpp and must match this module's behaviour.

Summary

Types

component()

@type component() :: %{
  unit: unit(),
  whole: non_neg_integer(),
  frac_milli: non_neg_integer()
}

error()

@type error() ::
  :empty
  | {:expected_p, String.t()}
  | :unexpected_end
  | {:invalid_number, String.t()}
  | {:date_after_t, unit()}
  | {:time_before_t, unit()}
  | :duplicate_t
  | :mixed_basic_extended
  | {:unexpected_token, String.t()}
  | {:non_canonical_order, unit()}
  | :fraction_not_on_last

unit()

@type unit() :: :y | :mo | :w | :d | :h | :mi | :s

Functions

parse(arg1)

@spec parse(String.t()) :: {:ok, [component()]} | {:error, error()}

total_milliseconds(components)

@spec total_milliseconds([component()]) :: non_neg_integer()

total_seconds(components)

@spec total_seconds([component()]) :: non_neg_integer()