73 lines
2 KiB
Elixir
73 lines
2 KiB
Elixir
defmodule RDF.DateTime do
|
|
@moduledoc """
|
|
`RDF.Datatype` for XSD dateTime.
|
|
"""
|
|
|
|
use RDF.Datatype, id: RDF.Datatype.NS.XSD.dateTime
|
|
|
|
|
|
# Special case for date and dateTime, for which 0 is not a valid year
|
|
def convert(%DateTime{year: 0} = value, opts), do: super(value, opts)
|
|
def convert(%DateTime{} = value, _), do: value
|
|
|
|
# Special case for date and dateTime, for which 0 is not a valid year
|
|
def convert(%NaiveDateTime{year: 0} = value, opts), do: super(value, opts)
|
|
def convert(%NaiveDateTime{} = value, _), do: value
|
|
|
|
def convert(value, opts) when is_binary(value) do
|
|
case DateTime.from_iso8601(value) do
|
|
{:ok, date_time, _} -> convert(date_time, opts)
|
|
|
|
{:error, :missing_offset} ->
|
|
case NaiveDateTime.from_iso8601(value) do
|
|
{:ok, date_time} -> convert(date_time, opts)
|
|
_ -> super(value, opts)
|
|
end
|
|
|
|
{:error, :invalid_time} ->
|
|
if String.contains?(value, "T24:00:00") do
|
|
with [day, tz] <- String.split(value, "T24:00:00", parts: 2),
|
|
{:ok, day} <- Date.from_iso8601(day)
|
|
do
|
|
"#{day |> Date.add(1) |> Date.to_string()}T00:00:00#{tz}"
|
|
|> convert(opts)
|
|
else
|
|
_ -> super(value, opts)
|
|
end
|
|
|
|
else
|
|
super(value, opts)
|
|
end
|
|
_ ->
|
|
super(value, opts)
|
|
end
|
|
end
|
|
|
|
def convert(value, opts), do: super(value, opts)
|
|
|
|
|
|
def canonical_lexical(%DateTime{} = value) do
|
|
DateTime.to_iso8601(value)
|
|
end
|
|
|
|
def canonical_lexical(%NaiveDateTime{} = value) do
|
|
NaiveDateTime.to_iso8601(value)
|
|
end
|
|
|
|
def tz(datetime_literal) do
|
|
if valid?(datetime_literal) do
|
|
lexical = lexical(datetime_literal)
|
|
case Regex.run(~r/([+-])(\d\d:\d\d)/, lexical) do
|
|
[_, sign, zone] ->
|
|
sign <> zone
|
|
_ ->
|
|
if String.ends_with?(lexical, "Z") do
|
|
"Z"
|
|
else
|
|
""
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
end
|