diff --git a/lib/rdf/xsd/datatypes/date.ex b/lib/rdf/xsd/datatypes/date.ex index aa689dd..2f73c29 100644 --- a/lib/rdf/xsd/datatypes/date.ex +++ b/lib/rdf/xsd/datatypes/date.ex @@ -16,8 +16,16 @@ defmodule RDF.XSD.Date do alias RDF.XSD + def_applicable_facet XSD.Facets.ExplicitTimezone def_applicable_facet XSD.Facets.Pattern + @doc false + def explicit_timezone_conform?(:required, {_, _}, _), do: true + def explicit_timezone_conform?(:required, _, _), do: false + def explicit_timezone_conform?(:prohibited, {_, _}, _), do: false + def explicit_timezone_conform?(:prohibited, _, _), do: true + def explicit_timezone_conform?(:optional, _, _), do: true + @doc false def pattern_conform?(pattern, _value, lexical) do XSD.Facets.Pattern.conform?(pattern, lexical) diff --git a/lib/rdf/xsd/datatypes/date_time.ex b/lib/rdf/xsd/datatypes/date_time.ex index f0cb811..506ec6f 100644 --- a/lib/rdf/xsd/datatypes/date_time.ex +++ b/lib/rdf/xsd/datatypes/date_time.ex @@ -12,8 +12,16 @@ defmodule RDF.XSD.DateTime do alias RDF.XSD + def_applicable_facet XSD.Facets.ExplicitTimezone def_applicable_facet XSD.Facets.Pattern + @doc false + def explicit_timezone_conform?(:required, %DateTime{}, _), do: true + def explicit_timezone_conform?(:required, _, _), do: false + def explicit_timezone_conform?(:prohibited, %NaiveDateTime{}, _), do: true + def explicit_timezone_conform?(:prohibited, _, _), do: false + def explicit_timezone_conform?(:optional, _, _), do: true + @doc false def pattern_conform?(pattern, _value, lexical) do XSD.Facets.Pattern.conform?(pattern, lexical) diff --git a/lib/rdf/xsd/datatypes/time.ex b/lib/rdf/xsd/datatypes/time.ex index 5aa1999..f5d61d6 100644 --- a/lib/rdf/xsd/datatypes/time.ex +++ b/lib/rdf/xsd/datatypes/time.ex @@ -16,8 +16,16 @@ defmodule RDF.XSD.Time do @tz_number_grammar ~r/\A(?:([\+\-])(\d{2}):(\d{2}))\Z/ + def_applicable_facet XSD.Facets.ExplicitTimezone def_applicable_facet XSD.Facets.Pattern + @doc false + def explicit_timezone_conform?(:required, {_, true}, _), do: true + def explicit_timezone_conform?(:required, _, _), do: false + def explicit_timezone_conform?(:prohibited, {_, true}, _), do: false + def explicit_timezone_conform?(:prohibited, _, _), do: true + def explicit_timezone_conform?(:optional, _, _), do: true + @doc false def pattern_conform?(pattern, _value, lexical) do XSD.Facets.Pattern.conform?(pattern, lexical) diff --git a/lib/rdf/xsd/facets/explicit_timezone.ex b/lib/rdf/xsd/facets/explicit_timezone.ex new file mode 100644 index 0000000..54eee0f --- /dev/null +++ b/lib/rdf/xsd/facets/explicit_timezone.ex @@ -0,0 +1,5 @@ +defmodule RDF.XSD.Facets.ExplicitTimezone do + @type t :: :required | :prohibited | :optional + + use RDF.XSD.Facet, name: :explicit_timezone, type: t +end diff --git a/test/support/test_datatypes.ex b/test/support/test_datatypes.ex index ae68bc5..b51fba2 100644 --- a/test/support/test_datatypes.ex +++ b/test/support/test_datatypes.ex @@ -67,4 +67,31 @@ defmodule RDF.TestDatatypes do def_facet_constraint RDF.XSD.Facets.MinInclusive, 0 def_facet_constraint RDF.XSD.Facets.MaxInclusive, 1 end + + defmodule DateTimeWithTz do + use RDF.XSD.Datatype.Restriction, + name: "datetime_with_tz", + id: "http://example.com/datetime-with-tz", + base: RDF.XSD.DateTime + + def_facet_constraint RDF.XSD.Facets.ExplicitTimezone, :required + end + + defmodule DateWithoutTz do + use RDF.XSD.Datatype.Restriction, + name: "date_with_tz", + id: "http://example.com/date-with-tz", + base: RDF.XSD.Date + + def_facet_constraint RDF.XSD.Facets.ExplicitTimezone, :prohibited + end + + defmodule CustomTime do + use RDF.XSD.Datatype.Restriction, + name: "time_with_tz", + id: "http://example.com/time-with-tz", + base: RDF.XSD.Time + + def_facet_constraint RDF.XSD.Facets.ExplicitTimezone, :optional + end end diff --git a/test/unit/xsd/datatypes/date_test.exs b/test/unit/xsd/datatypes/date_test.exs index a04f357..397b1e7 100644 --- a/test/unit/xsd/datatypes/date_test.exs +++ b/test/unit/xsd/datatypes/date_test.exs @@ -4,9 +4,11 @@ defmodule RDF.XSD.DateTest do name: "date", primitive: true, applicable_facets: [ + RDF.XSD.Facets.ExplicitTimezone, RDF.XSD.Facets.Pattern ], facets: %{ + explicit_timezone: nil, pattern: nil }, valid: %{ diff --git a/test/unit/xsd/datatypes/date_time_test.exs b/test/unit/xsd/datatypes/date_time_test.exs index 3470030..a0fd72a 100644 --- a/test/unit/xsd/datatypes/date_time_test.exs +++ b/test/unit/xsd/datatypes/date_time_test.exs @@ -6,9 +6,11 @@ defmodule RDF.XSD.DateTimeTest do name: "dateTime", primitive: true, applicable_facets: [ + RDF.XSD.Facets.ExplicitTimezone, RDF.XSD.Facets.Pattern ], facets: %{ + explicit_timezone: nil, pattern: nil }, valid: %{ diff --git a/test/unit/xsd/datatypes/time_test.exs b/test/unit/xsd/datatypes/time_test.exs index b8eb44c..232b503 100644 --- a/test/unit/xsd/datatypes/time_test.exs +++ b/test/unit/xsd/datatypes/time_test.exs @@ -4,9 +4,11 @@ defmodule RDF.XSD.TimeTest do name: "time", primitive: true, applicable_facets: [ + RDF.XSD.Facets.ExplicitTimezone, RDF.XSD.Facets.Pattern ], facets: %{ + explicit_timezone: nil, pattern: nil }, valid: %{ diff --git a/test/unit/xsd/facets/explicit_timezone_test.exs b/test/unit/xsd/facets/explicit_timezone_test.exs new file mode 100644 index 0000000..b77eece --- /dev/null +++ b/test/unit/xsd/facets/explicit_timezone_test.exs @@ -0,0 +1,26 @@ +defmodule RDF.XSD.Facets.ExplicitTimezoneTest do + use RDF.Test.Case + + import RDF.XSD.Datatype.Test.Case, only: [dt: 1] + + alias RDF.TestDatatypes.{DateTimeWithTz, DateWithoutTz, CustomTime} + + test "DateTimeWithTz" do + assert DateTimeWithTz.new(dt("2010-01-01T00:00:00Z")) |> RDF.Literal.valid?() + assert DateTimeWithTz.new("2010-01-01T00:00:00Z") |> RDF.Literal.valid?() + refute DateTimeWithTz.new(~N[2010-01-01T00:00:00]) |> RDF.Literal.valid?() + refute DateTimeWithTz.new("2010-01-01T00:00:00") |> RDF.Literal.valid?() + end + + test "DateWithoutTz" do + assert DateWithoutTz.new(~D[2010-01-01]) |> RDF.Literal.valid?() + assert DateWithoutTz.new("2010-01-01") |> RDF.Literal.valid?() + refute DateWithoutTz.new("2010-01-01Z") |> RDF.Literal.valid?() + end + + test "CustomTime" do + assert CustomTime.new(~T[00:00:00] ) |> RDF.Literal.valid?() + assert CustomTime.new("00:00:00Z") |> RDF.Literal.valid?() + assert CustomTime.new("00:00:00") |> RDF.Literal.valid?() + end +end