lib/fussy/validators/date_time.ex

defmodule Fussy.Validators.DateTime do
  @behaviour Fussy.Validator

  defstruct format: :iso8601

  @opaque t :: %__MODULE__{}

  @spec new() :: __MODULE__.t()
  def new(), do: %__MODULE__{}

  @impl true
  def validate(%__MODULE__{}, %DateTime{} = dt) do
    {:ok, dt}
  end

  @impl true
  def validate(%__MODULE__{format: :iso8601}, str) when is_binary(str) do
    case DateTime.from_iso8601(str) do
      {:ok, dt, _} ->
        {:ok, dt}

      {:error, _} ->
        {:error, ["must be a DateTime or an ISO8601 string"]}
    end
  end

  @impl true
  def validate(%__MODULE__{format: :iso8601}, _),
    do: {:error, ["must be a DateTime or an ISO8601 string"]}
end