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
|
XSD spec
|
||||||
- the logical operators and the Effective Boolean Value (EBV) coercion algorithm
|
- the logical operators and the Effective Boolean Value (EBV) coercion algorithm
|
||||||
from the XPath and SPARQL specs on `RDF.Boolean`
|
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.Term.equal?/2` and `RDF.Term.equal_value?/2`
|
||||||
- `RDF.LangString.match_language?/2`
|
- `RDF.LangString.match_language?/2`
|
||||||
- possibility to configure an application-specific default base IRI; for now it
|
- 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
|
use RDF.Datatype, id: RDF.Datatype.NS.XSD.dateTime
|
||||||
|
|
||||||
|
import RDF.Literal.Guards
|
||||||
|
|
||||||
|
|
||||||
def now() do
|
def now() do
|
||||||
new(DateTime.utc_now())
|
new(DateTime.utc_now())
|
||||||
|
@ -62,17 +64,32 @@ defmodule RDF.DateTime do
|
||||||
|
|
||||||
def tz(datetime_literal) do
|
def tz(datetime_literal) do
|
||||||
if valid?(datetime_literal) do
|
if valid?(datetime_literal) do
|
||||||
lexical = lexical(datetime_literal)
|
datetime_literal
|
||||||
case Regex.run(~r/([+-])(\d\d:\d\d)/, lexical) do
|
|> lexical()
|
||||||
[_, sign, zone] ->
|
|> RDF.DateTimeUtils.tz()
|
||||||
sign <> zone
|
end
|
||||||
_ ->
|
end
|
||||||
if String.ends_with?(lexical, "Z") do
|
|
||||||
"Z"
|
@doc """
|
||||||
else
|
Converts a datetime literal to a canonical string, preserving the zone information.
|
||||||
""
|
"""
|
||||||
end
|
def canonical_lexical_with_zone(%Literal{datatype: datatype} = literal)
|
||||||
end
|
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
|
||||||
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
|
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/
|
@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/
|
@tz_grammar ~r/\A(?:([\+\-])(\d{2}):(\d{2}))\Z/
|
||||||
|
|
||||||
|
@ -76,4 +78,35 @@ defmodule RDF.Time do
|
||||||
canonical_lexical(value) <> "Z"
|
canonical_lexical(value) <> "Z"
|
||||||
end
|
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
|
end
|
||||||
|
|
|
@ -123,4 +123,12 @@ defmodule RDF.DateTimeTest do
|
||||||
end
|
end
|
||||||
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
|
end
|
||||||
|
|
Loading…
Reference in a new issue