Add various utility functions on RDF.Time and RDF.DateTime
This commit is contained in:
parent
1fa369197e
commit
de25b5399b
5 changed files with 88 additions and 13 deletions
|
@ -20,7 +20,7 @@ This project adheres to [Semantic Versioning](http://semver.org/) and
|
|||
XSD spec
|
||||
- the logical operators and the Effective Boolean Value (EBV) coercion algorithm
|
||||
from the XPath and SPARQL specs on `RDF.Boolean`
|
||||
- `RDF.DateTime.now/0`
|
||||
- various functions on the `RDF.DateTime` and `RDF.Time` datatypes
|
||||
- `RDF.Term.equal?/2` and `RDF.Term.equal_value?/2`
|
||||
- `RDF.LangString.match_language?/2`
|
||||
- possibility to configure an application-specific default base IRI; for now it
|
||||
|
|
|
@ -5,6 +5,8 @@ defmodule RDF.DateTime do
|
|||
|
||||
use RDF.Datatype, id: RDF.Datatype.NS.XSD.dateTime
|
||||
|
||||
import RDF.Literal.Guards
|
||||
|
||||
|
||||
def now() do
|
||||
new(DateTime.utc_now())
|
||||
|
@ -59,20 +61,35 @@ defmodule RDF.DateTime do
|
|||
end
|
||||
|
||||
def tz(%Literal{value: %NaiveDateTime{}}), do: ""
|
||||
|
||||
|
||||
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
|
||||
datetime_literal
|
||||
|> lexical()
|
||||
|> RDF.DateTimeUtils.tz()
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Converts a datetime literal to a canonical string, preserving the zone information.
|
||||
"""
|
||||
def canonical_lexical_with_zone(%Literal{datatype: datatype} = literal)
|
||||
when is_xsd_datetime(datatype) do
|
||||
case tz(literal) do
|
||||
nil ->
|
||||
nil
|
||||
|
||||
zone when zone in ["Z", "", "+00:00"] ->
|
||||
canonical_lexical(literal.value)
|
||||
|
||||
zone ->
|
||||
literal
|
||||
|> lexical()
|
||||
|> String.replace_trailing(zone, "Z")
|
||||
|> DateTime.from_iso8601()
|
||||
|> elem(1)
|
||||
|> canonical_lexical()
|
||||
|> String.replace_trailing("Z", zone)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
17
lib/rdf/datatypes/date_time_utils.ex
Normal file
17
lib/rdf/datatypes/date_time_utils.ex
Normal file
|
@ -0,0 +1,17 @@
|
|||
defmodule RDF.DateTimeUtils do
|
||||
@moduledoc false
|
||||
|
||||
def tz(string) do
|
||||
case Regex.run(~r/([+-])(\d\d:\d\d)/, string) do
|
||||
[_, sign, zone] ->
|
||||
sign <> zone
|
||||
_ ->
|
||||
if String.ends_with?(string, "Z") do
|
||||
"Z"
|
||||
else
|
||||
""
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -5,6 +5,8 @@ defmodule RDF.Time do
|
|||
|
||||
use RDF.Datatype, id: RDF.Datatype.NS.XSD.time
|
||||
|
||||
import RDF.Literal.Guards
|
||||
|
||||
@grammar ~r/\A(\d{2}:\d{2}:\d{2}(?:\.\d+)?)((?:[\+\-]\d{2}:\d{2})|UTC|GMT|Z)?\Z/
|
||||
@tz_grammar ~r/\A(?:([\+\-])(\d{2}):(\d{2}))\Z/
|
||||
|
||||
|
@ -76,4 +78,35 @@ defmodule RDF.Time do
|
|||
canonical_lexical(value) <> "Z"
|
||||
end
|
||||
|
||||
def tz(time_literal) do
|
||||
if valid?(time_literal) do
|
||||
time_literal
|
||||
|> lexical()
|
||||
|> RDF.DateTimeUtils.tz()
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@doc """
|
||||
Converts a time literal to a canonical string, preserving the zone information.
|
||||
"""
|
||||
def canonical_lexical_with_zone(%Literal{datatype: datatype} = literal)
|
||||
when is_xsd_time(datatype) do
|
||||
case tz(literal) do
|
||||
nil ->
|
||||
nil
|
||||
|
||||
zone when zone in ["Z", "", "+00:00"] ->
|
||||
canonical_lexical(literal.value)
|
||||
|
||||
zone ->
|
||||
literal
|
||||
|> lexical()
|
||||
|> String.replace_trailing(zone, "")
|
||||
|> Time.from_iso8601!()
|
||||
|> canonical_lexical()
|
||||
|> Kernel.<>(zone)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -123,4 +123,12 @@ defmodule RDF.DateTimeTest do
|
|||
end
|
||||
end
|
||||
|
||||
test "canonical_lexical_with_zone/1" do
|
||||
assert RDF.date_time(~N[2010-01-01T12:34:56]) |> DateTime.canonical_lexical_with_zone() == "2010-01-01T12:34:56"
|
||||
assert RDF.date_time("2010-01-01T12:34:56") |> DateTime.canonical_lexical_with_zone() == "2010-01-01T12:34:56"
|
||||
assert RDF.date_time("2010-01-01T00:00:00+00:00") |> DateTime.canonical_lexical_with_zone() == "2010-01-01T00:00:00Z"
|
||||
assert RDF.date_time("2010-01-01T01:00:00+01:00") |> DateTime.canonical_lexical_with_zone() == "2010-01-01T01:00:00+01:00"
|
||||
assert RDF.date_time("2010-01-01 01:00:00+01:00") |> DateTime.canonical_lexical_with_zone() == "2010-01-01T01:00:00+01:00"
|
||||
end
|
||||
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue