Koyomi.DateTimeRange (Koyomi v0.2.1)

Copy Markdown View Source

An Ecto type for a span of time: a start and an end instant, the start included and the end left out ([from, to)), as for a booking from 14:00 to 16:00.

The :storage option says how the span is stored, so that the same field works with any database:

  • :postgres (the default) - a PostgreSQL tstzrange column. It needs :postgrex.
  • :string - a text column with an ISO 8601 interval in UTC, "2027-03-15T13:00:00Z/2027-03-15T15:00:00Z": SQLite, MySQL, and embedded schemas.
  • :map - a map column (JSON in SQLite and MySQL) with %{"from" => "2027-03-15T13:00:00Z", "to" => "2027-03-15T15:00:00Z"}.
# PostgreSQL
add :booking, :tstzrange
field :booking, Koyomi.DateTimeRange

# SQLite (ecto_sqlite3), MySQL
add :booking, :string
field :booking, Koyomi.DateTimeRange, storage: :string

A query for the spans that hold an instant needs PostgreSQL; with another database, two :utc_datetime columns can be queried as instants.

The value is a %Koyomi.DateTimeRange{from: DateTime, to: DateTime}, in UTC. The type casts this struct, a {from, to} tuple, a map with "from" and "to" (two DateTime, or two ISO 8601 strings with an offset, "2027-03-15T14:00:00+01:00", as two date and time pickers with a time_zone post them), and an ISO 8601 interval of two such strings. Both ends empty cast to nil. A span that ends before it starts is invalid.

Summary

Functions

Casts a value to a Koyomi.DateTimeRange (see the module docs for the forms it takes).

Dumps a span to a PostgreSQL tstzrange (Postgrex.Range), [from, to).

Loads a PostgreSQL tstzrange (Postgrex.Range); a span without a bound (infinite) or an empty one loads as nil.

The span as ISO 8601 strings in UTC: %{"from" => iso, "to" => iso}.

Types

t()

@type t() :: %Koyomi.DateTimeRange{from: DateTime.t(), to: DateTime.t()}

Functions

cast(map)

@spec cast(term()) :: {:ok, t() | nil} | :error | {:error, keyword()}

Casts a value to a Koyomi.DateTimeRange (see the module docs for the forms it takes).

dump(arg1)

@spec dump(t() | nil) :: {:ok, term()} | :error

Dumps a span to a PostgreSQL tstzrange (Postgrex.Range), [from, to).

duration(date_time_range, unit \\ :second)

@spec duration(t(), System.time_unit()) :: integer()

The length of the span.

Examples

iex> {:ok, span} = Koyomi.DateTimeRange.cast(%{"from" => "2027-03-15T14:00:00Z", "to" => "2027-03-15T16:30:00Z"})
iex> Koyomi.DateTimeRange.duration(span, :minute)
150

load(arg1)

@spec load(term()) :: {:ok, t() | nil} | :error

Loads a PostgreSQL tstzrange (Postgrex.Range); a span without a bound (infinite) or an empty one loads as nil.

to_params(date_time_range)

@spec to_params(t()) :: %{required(String.t()) => String.t()}

The span as ISO 8601 strings in UTC: %{"from" => iso, "to" => iso}.

Examples

iex> {:ok, span} = Koyomi.DateTimeRange.cast(%{"from" => "2027-03-15T14:00:00+01:00", "to" => "2027-03-15T16:00:00+01:00"})
iex> Koyomi.DateTimeRange.to_params(span)
%{"from" => "2027-03-15T13:00:00Z", "to" => "2027-03-15T15:00:00Z"}