Packages
zoi
0.5.0
0.18.7
0.18.6
0.18.5
0.18.4
0.18.3
0.18.2
0.18.1
0.18.0
0.17.4
0.17.3
0.17.2
0.17.1
0.17.0
0.16.1
0.16.0
0.15.0
0.14.1
0.14.0
0.13.1
0.13.0
0.12.1
0.12.0
0.11.1
0.11.0
0.10.7
0.10.6
0.10.5
0.10.4
0.10.3
0.10.2
0.10.1
0.10.0
0.9.1
0.9.0
0.9.0-rc.1
0.9.0-rc.0
0.8.4
0.8.3
0.8.2
0.8.1
0.8.0
0.7.4
0.7.3
0.7.2
0.7.1
0.7.0
0.6.6
0.6.5
0.6.4
0.6.3
0.6.2
0.6.1
0.6.0
0.5.7
0.5.6
0.5.5
0.5.4
0.5.3
0.5.2
0.5.1
0.5.0
0.4.0
0.3.4
0.3.3
0.3.2
0.3.1
0.3.0
0.2.3
0.2.2
0.2.1
0.2.0
0.1.3
0.1.2
0.1.1
0.1.0
Zoi is a schema validation library for Elixir, designed to provide a simple and flexible way to define and validate data.
Current section
Files
Jump to
Current section
Files
lib/zoi/iso.ex
defmodule Zoi.ISO do
@moduledoc """
This module defines schemas for ISO time, date, and datetime formats,
along with transformations to convert them into Elixir's native types.
It includes built-in transformations to convert ISO time, date, and datetime
strings into `%Time{}`, `%Date{}`, and `%DateTime{}` structs.
"""
@doc """
Defines a time type schema.
## Example
iex> schema = Zoi.ISO.time()
iex> Zoi.parse(schema, "12:34:56")
{:ok, "12:34:56"}
iex> Zoi.parse(schema, "25:00:00")
{:error, [%Zoi.Error{message: "invalid type: must be an ISO time"}]}
"""
@doc group: "Basic Types"
defdelegate time(opts \\ []), to: Zoi.ISO.Time, as: :new
@doc """
Defines a date type schema.
## Example
iex> schema = Zoi.ISO.date()
iex> Zoi.parse(schema, "2025-08-07")
{:ok, "2025-08-07"}
iex> Zoi.parse(schema, "2025-02-30")
{:error, [%Zoi.Error{message: "invalid type: must be an ISO date"}]}
"""
@doc group: "Basic Types"
defdelegate date(opts \\ []), to: Zoi.ISO.Date, as: :new
@doc """
Defines a datetime type schema.
## Example
iex> schema = Zoi.ISO.datetime()
iex> Zoi.parse(schema, "2025-08-07T10:04:22+03:00")
{:ok, "2025-08-07T10:04:22+03:00"}
iex> schema = Zoi.ISO.datetime()
iex> Zoi.parse(schema, 1754646043)
{:error, [%Zoi.Error{message: "invalid type: must be an ISO datetime"}]}
"""
@doc group: "Basic Types"
defdelegate datetime(opts \\ []), to: Zoi.ISO.DateTime, as: :new
@doc """
Defines a naive datetime type schema.
## Example
iex> schema = Zoi.ISO.naive_datetime()
iex> Zoi.parse(schema, "2025-08-07T10:04:22")
{:ok, "2025-08-07T10:04:22"}
iex> schema = Zoi.ISO.naive_datetime()
iex> Zoi.parse(schema, 1754646043)
{:error, [%Zoi.Error{message: "invalid type: must be an ISO naive datetime"}]}
"""
@doc group: "Basic Types"
defdelegate naive_datetime(opts \\ []), to: Zoi.ISO.NaiveDateTime, as: :new
# Transforms
@doc """
Converts `Zoi.ISO.time()` to `%Time{}` struct.
## Example
iex> schema = Zoi.ISO.time() |> Zoi.ISO.to_time_struct()
iex> Zoi.parse(schema, "12:34:56")
{:ok, ~T[12:34:56]}
"""
@doc group: "Transforms"
def to_time_struct(schema) do
schema
|> Zoi.transform({__MODULE__, :__transform__, [[:to_time]]})
end
@doc """
Converts `Zoi.ISO.date()` to `%Date{}` struct.
## Example
iex> schema = Zoi.ISO.date() |> Zoi.ISO.to_date_struct()
iex> Zoi.parse(schema, "2025-08-07")
{:ok, ~D[2025-08-07]}
"""
@doc group: "Transforms"
def to_date_struct(schema) do
schema
|> Zoi.transform({__MODULE__, :__transform__, [[:to_date]]})
end
@doc """
Converts `Zoi.ISO.datetime()` to `%DateTime{}` struct.
## Example
iex> schema = Zoi.ISO.datetime() |> Zoi.ISO.to_datetime_struct()
iex> Zoi.parse(schema, "2025-08-07T10:04:22+03:00")
{:ok, ~U[2025-08-07 07:04:22Z]}
"""
@doc group: "Transforms"
def to_datetime_struct(schema) do
schema
|> Zoi.transform({__MODULE__, :__transform__, [[:to_datetime]]})
end
@doc """
Converts `Zoi.ISO.naive_datetime()` to `%NaiveDateTime{}` struct.
## Example
iex> schema = Zoi.ISO.naive_datetime() |> Zoi.ISO.to_naive_datetime_struct()
iex> Zoi.parse(schema, "2025-08-07T10:04:22")
{:ok, ~N[2025-08-07 10:04:22]}
"""
@doc group: "Transforms"
def to_naive_datetime_struct(schema) do
schema
|> Zoi.transform({__MODULE__, :__transform__, [[:to_naive_datetime]]})
end
# Transforms MFAs
@doc false
def __transform__(input, args, ctx: ctx) do
do_transform(ctx.schema, input, args)
end
def do_transform(%Zoi.ISO.Time{}, input, [:to_time]) do
# since `Zoi.ISO.Time` already validates the input as an ISO time,
# we can safely parse it to a Time struct
{:ok, parsed} = Time.from_iso8601(input)
{:ok, parsed}
end
def do_transform(%Zoi.ISO.Date{}, input, [:to_date]) do
# since `Zoi.ISO.Date` already validates the input as an ISO date,
# we can safely parse it to a Date struct
{:ok, parsed} = Date.from_iso8601(input)
{:ok, parsed}
end
def do_transform(%Zoi.ISO.DateTime{}, input, [:to_datetime]) do
# since `Zoi.ISO.DateTime` already validates the input as an ISO datetime,
# we can safely parse it to a DateTime struct
{:ok, parsed, _offset} = DateTime.from_iso8601(input)
{:ok, parsed}
end
def do_transform(%Zoi.ISO.NaiveDateTime{}, input, [:to_naive_datetime]) do
# since `Zoi.ISO.NaiveDateTime` already validates the input as an ISO naive datetime,
# we can safely parse it to a NaiveDateTime struct
{:ok, parsed} = NaiveDateTime.from_iso8601(input)
{:ok, parsed}
end
# coveralls-ignore-start
def do_transform(_schema, input, _args) do
# Default to the input if there is no type pattern match
{:ok, input}
end
# coveralls-ignore-stop
end