JENA-149: Duration equality by value. Canonicalise the date/time duration based on year-month and day-time.
Project: http://git-wip-us.apache.org/repos/asf/jena/repo Commit: http://git-wip-us.apache.org/repos/asf/jena/commit/1694e7fb Tree: http://git-wip-us.apache.org/repos/asf/jena/tree/1694e7fb Diff: http://git-wip-us.apache.org/repos/asf/jena/diff/1694e7fb Branch: refs/heads/JENA-507 Commit: 1694e7fb34ac325a0f1b5308a4772624e8100cb2 Parents: 3570b14 Author: Andy Seaborne <[email protected]> Authored: Mon Jan 11 09:03:59 2016 +0000 Committer: Andy Seaborne <[email protected]> Committed: Mon Jan 11 09:07:09 2016 +0000 ---------------------------------------------------------------------- .../jena/datatypes/xsd/AbstractDateTime.java | 4 +- .../apache/jena/datatypes/xsd/XSDDuration.java | 91 +++++++++++++++- .../jena/datatypes/TestDatatypeValues.java | 104 +++++++++++++++++++ .../org/apache/jena/datatypes/TestPackage.java | 1 + 4 files changed, 197 insertions(+), 3 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/jena/blob/1694e7fb/jena-core/src/main/java/org/apache/jena/datatypes/xsd/AbstractDateTime.java ---------------------------------------------------------------------- diff --git a/jena-core/src/main/java/org/apache/jena/datatypes/xsd/AbstractDateTime.java b/jena-core/src/main/java/org/apache/jena/datatypes/xsd/AbstractDateTime.java index 1f4793a..fbbf950 100644 --- a/jena-core/src/main/java/org/apache/jena/datatypes/xsd/AbstractDateTime.java +++ b/jena-core/src/main/java/org/apache/jena/datatypes/xsd/AbstractDateTime.java @@ -79,7 +79,7 @@ public class AbstractDateTime implements Comparable<AbstractDateTime> { * @return an order flag - one of LESS_THAN, EQUAL, GREATER_THEN, INDETERMINATE */ public int compare(AbstractDateTime other) { - return compareDates(data, other.data, true); + return compareValues(data, other.data, true); } /** @@ -155,7 +155,7 @@ public class AbstractDateTime implements Comparable<AbstractDateTime> { * @param strict * @return less, greater, less_equal, greater_equal, equal */ - protected short compareDates(int[] date1, int[] date2, boolean strict) { + protected short compareValues(int[] date1, int[] date2, boolean strict) { if ( date1[utc]==date2[utc] ) { return compareOrder(date1, date2); } http://git-wip-us.apache.org/repos/asf/jena/blob/1694e7fb/jena-core/src/main/java/org/apache/jena/datatypes/xsd/XSDDuration.java ---------------------------------------------------------------------- diff --git a/jena-core/src/main/java/org/apache/jena/datatypes/xsd/XSDDuration.java b/jena-core/src/main/java/org/apache/jena/datatypes/xsd/XSDDuration.java index 4928ae6..3fc405c 100644 --- a/jena-core/src/main/java/org/apache/jena/datatypes/xsd/XSDDuration.java +++ b/jena-core/src/main/java/org/apache/jena/datatypes/xsd/XSDDuration.java @@ -19,6 +19,7 @@ package org.apache.jena.datatypes.xsd; import java.math.BigDecimal; +import java.util.Arrays ; import org.apache.jena.datatypes.xsd.impl.XSDAbstractDateTimeType ; @@ -193,8 +194,11 @@ public class XSDDuration extends AbstractDateTime { * return GREATER_THAN if date1 is greater than OR equal to date2 */ @Override - protected short compareDates(int[] date1, int[] date2, boolean strict) { + protected short compareValues(int[] date1, int[] date2, boolean strict) { + date1 = canonical(date1) ; + date2 = canonical(date2) ; + //REVISIT: this is unoptimazed vs of comparing 2 durations // Algorithm is described in 3.2.6.2 W3C Schema Datatype specs // @@ -266,6 +270,37 @@ public class XSDDuration extends AbstractDateTime { } return resultA; } + + /** + * Equality function (value based). + */ + @Override + public boolean equals(Object obj) { + if ( this == obj ) + return true ; + if ( obj == null ) + return false ; + if (obj instanceof XSDDuration) { + XSDDuration dur = (XSDDuration) obj; + int[] data1 = canonical(this.data) ; + int[] data2 = canonical(dur.data) ; + for (int i = 0; i < data1.length; i++) { + if (data1[i] != data2[i]) + return false; + } + return true; + } + return super.equals(obj) ; + } + + @Override + public int hashCode() { + int[] data1 = canonical(this.data) ; + int hash = 1816 ; + for ( int aData : data1 ) + hash = ( hash << 1 ) ^ aData; + return hash; + } private int[] addDuration(int[] date, int index, int[] duration) { @@ -323,4 +358,58 @@ public class XSDDuration extends AbstractDateTime { return duration; } + + // XXX Signedness? + // Day-time, year-month canonicalization. + private static int[] canonical(int[] val) { + val = Arrays.copyOf(val, val.length) ; + + while ( val[ms] >= 1000 ) { + val[s] += 1 ; + val[ms] -= 1000 ; + } + while ( val[ms] <= -1000 ) { + val[s] -= 1 ; + val[ms] += 1000 ; + } + + while ( val[s] >= 60 ) { + val[m] += 1 ; + val[s] -= 60 ; + } + while ( val[s] <= -60 ) { + val[m] -= 1 ; + val[s] += 60 ; + } + + + while ( val[m] >= 60 ) { + val[h] += 1 ; + val[m] -= 60 ; + } + while ( val[m] <= -60 ) { + val[h] -= 1 ; + val[m] += 60 ; + } + + while ( val[h] >= 24 ) { + val[D] += 1 ; + val[h] -= 24 ; + } + while ( val[h] <= -24 ) { + val[D] -= 1 ; + val[h] += 24 ; + } + + while ( val[M] >= 12 ) { + val[CY] += 1 ; + val[M] -= 12 ; + } + while ( val[M] <= -12 ) { + val[CY] -= 1 ; + val[M] += 12 ; + } + + return val ; + } } http://git-wip-us.apache.org/repos/asf/jena/blob/1694e7fb/jena-core/src/test/java/org/apache/jena/datatypes/TestDatatypeValues.java ---------------------------------------------------------------------- diff --git a/jena-core/src/test/java/org/apache/jena/datatypes/TestDatatypeValues.java b/jena-core/src/test/java/org/apache/jena/datatypes/TestDatatypeValues.java new file mode 100644 index 0000000..b57c8de --- /dev/null +++ b/jena-core/src/test/java/org/apache/jena/datatypes/TestDatatypeValues.java @@ -0,0 +1,104 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jena.datatypes; + +import org.apache.jena.datatypes.xsd.XSDDatatype ; +import org.apache.jena.datatypes.xsd.XSDDuration ; +import org.apache.jena.graph.Node ; +import org.apache.jena.graph.NodeFactory ; +import org.junit.Assert ; +import org.junit.Test ; + +/** Tests on values */ +public class TestDatatypeValues { + + // Duration. + + @Test public void duration_01() { + durationCompareTest(0, "PT1M", "PT1M") ; + } + + @Test public void duration_02() { + durationCompareTest(0, "PT1M", "P0YT1M0S") ; + } + + @Test public void duration_03() { + durationCompareTest(0, "P1Y", "P1Y0M") ; + } + + @Test public void duration_04() { + durationCompareTest(1, "P2Y", "P1Y") ; + } + + @Test public void duration_05() { + durationCompareTest(0, "-P2Y", "-P2Y") ; + } + + @Test public void duration_06() { + durationCompareTest(-1, "-P2Y", "-P1Y") ; + } + + @Test public void duration_07() { + durationCompareTest(-1, "P2Y", "P4Y") ; + } + + @Test public void duration_10() { + durationCompareTest(0, "P1Y", "P12M") ; + } + + @Test public void duration_11() { + durationCompareTest(0, "P2Y", "P24M") ; + } + + @Test public void duration_12() { + durationCompareTest(0, "P1D", "PT24H") ; + } + + @Test public void duration_13() { + durationCompareTest(0, "P1D", "PT1440M") ; + } + + @Test public void duration_14() { + durationCompareTest(0, "P1D", "PT86400S") ; + } + + @Test public void duration_20() { + durationCompareTest(0, "-P1D", "-PT86400S") ; + } + + private static void durationCompareTest(int expected, String lex1, String lex2) { + durationCompareTest(expected, lex1, XSDDatatype.XSDduration, lex2, XSDDatatype.XSDduration); + } + + private static void durationCompareTest(int expected, String lex1, XSDDatatype dt1, String lex2, XSDDatatype dt2) { + Node d1 = NodeFactory.createLiteral(lex1, null, XSDDatatype.XSDduration); + Node d2 = NodeFactory.createLiteral(lex2, null, XSDDatatype.XSDduration); + XSDDuration dur1 = (XSDDuration) d1.getLiteralValue(); + XSDDuration dur2 = (XSDDuration) d2.getLiteralValue(); + int cmp = dur1.compare(dur2) ; + + Assert.assertEquals("Compare: "+lex1+" and "+lex2, expected, cmp) ; + if ( cmp == 0 ) { + Assert.assertEquals("Not hash compatible: "+lex1+" and "+lex2, d1.hashCode(), d2.hashCode()) ; + Assert.assertTrue("Not equal: "+lex1+" and "+lex2, d1.sameValueAs(d2)) ; + } else { + Assert.assertFalse("Equal: "+lex1+" and "+lex2, d1.sameValueAs(d2)) ; + } + } +} http://git-wip-us.apache.org/repos/asf/jena/blob/1694e7fb/jena-core/src/test/java/org/apache/jena/datatypes/TestPackage.java ---------------------------------------------------------------------- diff --git a/jena-core/src/test/java/org/apache/jena/datatypes/TestPackage.java b/jena-core/src/test/java/org/apache/jena/datatypes/TestPackage.java index 782d88a..a996cc6 100644 --- a/jena-core/src/test/java/org/apache/jena/datatypes/TestPackage.java +++ b/jena-core/src/test/java/org/apache/jena/datatypes/TestPackage.java @@ -36,5 +36,6 @@ public class TestPackage extends TestSuite { private TestPackage() { super("datatypes"); addTest(new JUnit4TestAdapter(TestDatatypes.class)) ; + addTest(new JUnit4TestAdapter(TestDatatypeValues.class)) ; } }
