sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject [sis] branch geoapi-4.0 updated: Initial implementation of TemporalFunction.
Date Sat, 24 Aug 2019 15:11:40 GMT
This is an automated email from the ASF dual-hosted git repository.

desruisseaux pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git


The following commit(s) were added to refs/heads/geoapi-4.0 by this push:
     new 86e4d51  Initial implementation of TemporalFunction.
86e4d51 is described below

commit 86e4d51108d70451178397e57db31ce2b2704d81
Author: Martin Desruisseaux <martin.desruisseaux@geomatys.com>
AuthorDate: Sat Aug 24 17:11:12 2019 +0200

    Initial implementation of TemporalFunction.
---
 .../org/apache/sis/filter/ArithmeticFunction.java  |  16 +-
 .../java/org/apache/sis/filter/BinaryFunction.java |  14 +
 .../org/apache/sis/filter/ComparisonFunction.java  |  50 +-
 .../apache/sis/filter/DefaultFilterFactory.java    |   6 +-
 .../org/apache/sis/filter/TemporalFunction.java    | 621 ++++++++++++++++-----
 .../java/org/apache/sis/filter/PeriodLiteral.java  | 116 ++++
 .../apache/sis/filter/TemporalFunctionTest.java    | 159 ++++--
 7 files changed, 766 insertions(+), 216 deletions(-)

diff --git a/core/sis-feature/src/main/java/org/apache/sis/filter/ArithmeticFunction.java b/core/sis-feature/src/main/java/org/apache/sis/filter/ArithmeticFunction.java
index 3a5705b..f998ddf 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/filter/ArithmeticFunction.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/filter/ArithmeticFunction.java
@@ -133,7 +133,7 @@ abstract class ArithmeticFunction extends BinaryFunction implements BinaryExpres
      * The "Add" (+) expression.
      */
     static final class Add extends ArithmeticFunction implements org.opengis.filter.expression.Add {
-        /** For cross-version compatibility. */
+        /** For cross-version compatibility during (de)serialization. */
         private static final long serialVersionUID = 5445433312445869201L;
 
         /** Description of results of the {@value #NAME} expression. */
@@ -156,7 +156,7 @@ abstract class ArithmeticFunction extends BinaryFunction implements BinaryExpres
         @Override protected Number applyAsInteger (BigInteger left, BigInteger right) {return left.add(right);}
         @Override protected Number applyAsLong    (long       left, long       right) {return Math.addExact(left, right);}
 
-        /** Implementation of the visitor pattern. */
+        /** Implementation of the visitor pattern (not used by Apache SIS). */
         @Override public Object accept(ExpressionVisitor visitor, Object extraData) {
             return visitor.visit(this, extraData);
         }
@@ -167,7 +167,7 @@ abstract class ArithmeticFunction extends BinaryFunction implements BinaryExpres
      * The "Sub" (−) expression.
      */
     static final class Subtract extends ArithmeticFunction implements org.opengis.filter.expression.Subtract {
-        /** For cross-version compatibility. */
+        /** For cross-version compatibility during (de)serialization. */
         private static final long serialVersionUID = 3048878022726271508L;
 
         /** Description of results of the {@value #NAME} expression. */
@@ -190,7 +190,7 @@ abstract class ArithmeticFunction extends BinaryFunction implements BinaryExpres
         @Override protected Number applyAsInteger (BigInteger left, BigInteger right) {return left.subtract(right);}
         @Override protected Number applyAsLong    (long       left, long       right) {return Math.subtractExact(left, right);}
 
-        /** Implementation of the visitor pattern. */
+        /** Implementation of the visitor pattern (not used by Apache SIS). */
         @Override public Object accept(ExpressionVisitor visitor, Object extraData) {
             return visitor.visit(this, extraData);
         }
@@ -201,7 +201,7 @@ abstract class ArithmeticFunction extends BinaryFunction implements BinaryExpres
      * The "Mul" (×) expression.
      */
     static final class Multiply extends ArithmeticFunction implements org.opengis.filter.expression.Multiply {
-        /** For cross-version compatibility. */
+        /** For cross-version compatibility during (de)serialization. */
         private static final long serialVersionUID = -1300022614832645625L;
 
         /** Description of results of the {@value #NAME} expression. */
@@ -224,7 +224,7 @@ abstract class ArithmeticFunction extends BinaryFunction implements BinaryExpres
         @Override protected Number applyAsInteger (BigInteger left, BigInteger right) {return left.multiply(right);}
         @Override protected Number applyAsLong    (long       left, long       right) {return Math.multiplyExact(left, right);}
 
-        /** Implementation of the visitor pattern. */
+        /** Implementation of the visitor pattern (not used by Apache SIS). */
         @Override public Object accept(ExpressionVisitor visitor, Object extraData) {
             return visitor.visit(this, extraData);
         }
@@ -235,7 +235,7 @@ abstract class ArithmeticFunction extends BinaryFunction implements BinaryExpres
      * The "Div" (÷) expression.
      */
     static final class Divide extends ArithmeticFunction implements org.opengis.filter.expression.Divide {
-        /** For cross-version compatibility. */
+        /** For cross-version compatibility during (de)serialization. */
         private static final long serialVersionUID = -7709291845568648891L;
 
         /** Description of results of the {@value #NAME} expression. */
@@ -273,7 +273,7 @@ abstract class ArithmeticFunction extends BinaryFunction implements BinaryExpres
             }
         }
 
-        /** Implementation of the visitor pattern. */
+        /** Implementation of the visitor pattern (not used by Apache SIS). */
         @Override public Object accept(ExpressionVisitor visitor, Object extraData) {
             return visitor.visit(this, extraData);
         }
diff --git a/core/sis-feature/src/main/java/org/apache/sis/filter/BinaryFunction.java b/core/sis-feature/src/main/java/org/apache/sis/filter/BinaryFunction.java
index d0e0b12..943f5c5 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/filter/BinaryFunction.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/filter/BinaryFunction.java
@@ -77,6 +77,9 @@ abstract class BinaryFunction extends Node {
     /**
      * Returns the first of the two expressions to be used by this function.
      * This is the value specified at construction time.
+     *
+     * @see org.opengis.filter.BinaryComparisonOperator#getExpression1()
+     * @see org.opengis.filter.temporal.BinaryTemporalOperator#getExpression1()
      */
     public final Expression getExpression1() {
         return expression1;
@@ -85,6 +88,9 @@ abstract class BinaryFunction extends Node {
     /**
      * Returns the second of the two expressions to be used by this function.
      * This is the value specified at construction time.
+     *
+     * @see org.opengis.filter.BinaryComparisonOperator#getExpression1()
+     * @see org.opengis.filter.temporal.BinaryTemporalOperator#getExpression2()
      */
     public final Expression getExpression2() {
         return expression2;
@@ -102,10 +108,13 @@ abstract class BinaryFunction extends Node {
     /**
      * Evaluates the expression for producing a result of numeric type.
      * This method delegates to one of the {@code applyAs(…)} methods.
+     * If no {@code applyAs(…)} implementations can return null values,
+     * this this method never return {@code null}.
      *
      * @param  left   the left operand. Can not be null.
      * @param  right  the right operand. Can not be null.
      * @return result of this function applied on the two given operands.
+     *         May be {@code null} only if an {@code applyAs(…)} implementation returned a null value.
      * @throws ArithmeticException if the operation overflows the capacity of the type used.
      */
     protected final Number apply(final Number left, final Number right) {
@@ -139,6 +148,7 @@ abstract class BinaryFunction extends Node {
      * Calculates this function using given operands of {@code long} primitive type. If this function is a
      * filter, then this method should returns an {@link Integer} value 0 or 1 for false or true respectively.
      * Otherwise the result is usually a {@link Long}, except for division which may produce a floating point number.
+     * This method may return {@code null} if the operation can not apply on numbers.
      *
      * @throws ArithmeticException if the operation overflows the 64 bits integer capacity.
      */
@@ -148,6 +158,7 @@ abstract class BinaryFunction extends Node {
      * Calculates this function using given operands of {@code double} primitive type. If this function is a
      * filter, then this method should returns an {@link Integer} value 0 or 1 for false or true respectively.
      * Otherwise the result is usually a {@link Double}.
+     * This method may return {@code null} if the operation can not apply on numbers.
      */
     protected abstract Number applyAsDouble(double left, double right);
 
@@ -155,6 +166,7 @@ abstract class BinaryFunction extends Node {
      * Calculates this function using given operands of {@code Fraction} type. If this function is a filter,
      * then this method should returns an {@link Integer} value 0 or 1 for false or true respectively.
      * Otherwise the result is usually a {@link Fraction}.
+     * This method may return {@code null} if the operation can not apply on numbers.
      */
     protected abstract Number applyAsFraction(Fraction left, Fraction right);
 
@@ -162,6 +174,7 @@ abstract class BinaryFunction extends Node {
      * Calculates this function using given operands of {@code BigInteger} type. If this function is a filter,
      * then this method should returns an {@link Integer} value 0 or 1 for false or true respectively.
      * Otherwise the result is usually a {@link BigInteger}.
+     * This method may return {@code null} if the operation can not apply on numbers.
      */
     protected abstract Number applyAsInteger(BigInteger left, BigInteger right);
 
@@ -169,6 +182,7 @@ abstract class BinaryFunction extends Node {
      * Calculates this function using given operands of {@code BigDecimal} type. If this function is a filter,
      * then this method should returns an {@link Integer} value 0 or 1 for false or true respectively.
      * Otherwise the result is usually a {@link BigDecimal}.
+     * This method may return {@code null} if the operation can not apply on numbers.
      */
     protected abstract Number applyAsDecimal(BigDecimal left, BigDecimal right);
 
diff --git a/core/sis-feature/src/main/java/org/apache/sis/filter/ComparisonFunction.java b/core/sis-feature/src/main/java/org/apache/sis/filter/ComparisonFunction.java
index 9e2f78e..dcfccfd 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/filter/ComparisonFunction.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/filter/ComparisonFunction.java
@@ -333,7 +333,7 @@ abstract class ComparisonFunction extends BinaryFunction implements BinaryCompar
      * This method handles a few types from the {@link java.time} package and legacy types like
      * {@link Date} (with a special case for SQL dates) and {@link Calendar}.
      */
-    private static Instant toInstant(final Object value) {
+    static Instant toInstant(final Object value) {
         if (value instanceof Instant) {
             return (Instant) value;
         } else if (value instanceof OffsetDateTime) {
@@ -503,13 +503,13 @@ abstract class ComparisonFunction extends BinaryFunction implements BinaryCompar
 
 
     /**
-     * The "LessThan" {@literal (<)} expression.
+     * The {@value #NAME} {@literal (<)} filter.
      */
     static final class LessThan extends ComparisonFunction implements org.opengis.filter.PropertyIsLessThan {
-        /** For cross-version compatibility. */
+        /** For cross-version compatibility during (de)serialization. */
         private static final long serialVersionUID = 6126039112844823196L;
 
-        /** Creates a new expression for the {@value #NAME} operation. */
+        /** Creates a new filter for the {@value #NAME} operation. */
         LessThan(Expression expression1, Expression expression2, boolean isMatchingCase, MatchAction matchAction) {
             super(expression1, expression2, isMatchingCase, matchAction);
         }
@@ -530,7 +530,7 @@ abstract class ComparisonFunction extends BinaryFunction implements BinaryCompar
         @Override protected boolean compare      (ChronoLocalDateTime<?> left, ChronoLocalDateTime<?> right) {return left.isBefore(right);}
         @Override protected boolean compare      (ChronoZonedDateTime<?> left, ChronoZonedDateTime<?> right) {return left.isBefore(right);}
 
-        /** Implementation of the visitor pattern. */
+        /** Implementation of the visitor pattern (not used by Apache SIS). */
         @Override public Object accept(FilterVisitor visitor, Object extraData) {
             return visitor.visit(this, extraData);
         }
@@ -538,13 +538,13 @@ abstract class ComparisonFunction extends BinaryFunction implements BinaryCompar
 
 
     /**
-     * The "LessThanOrEqualTo" (≤) expression.
+     * The {@value #NAME} (≤) filter.
      */
     static final class LessThanOrEqualTo extends ComparisonFunction implements org.opengis.filter.PropertyIsLessThanOrEqualTo {
-        /** For cross-version compatibility. */
+        /** For cross-version compatibility during (de)serialization. */
         private static final long serialVersionUID = 6357459227911760871L;
 
-        /** Creates a new expression for the {@value #NAME} operation. */
+        /** Creates a new filter for the {@value #NAME} operation. */
         LessThanOrEqualTo(Expression expression1, Expression expression2, boolean isMatchingCase, MatchAction matchAction) {
             super(expression1, expression2, isMatchingCase, matchAction);
         }
@@ -565,7 +565,7 @@ abstract class ComparisonFunction extends BinaryFunction implements BinaryCompar
         @Override protected boolean compare      (ChronoLocalDateTime<?> left, ChronoLocalDateTime<?> right) {return !left.isAfter(right);}
         @Override protected boolean compare      (ChronoZonedDateTime<?> left, ChronoZonedDateTime<?> right) {return !left.isAfter(right);}
 
-        /** Implementation of the visitor pattern. */
+        /** Implementation of the visitor pattern (not used by Apache SIS). */
         @Override public Object accept(FilterVisitor visitor, Object extraData) {
             return visitor.visit(this, extraData);
         }
@@ -573,13 +573,13 @@ abstract class ComparisonFunction extends BinaryFunction implements BinaryCompar
 
 
     /**
-     * The "GreaterThan" {@literal (>)} expression.
+     * The {@value #NAME} {@literal (>)} filter.
      */
     static final class GreaterThan extends ComparisonFunction implements org.opengis.filter.PropertyIsGreaterThan {
-        /** For cross-version compatibility. */
+        /** For cross-version compatibility during (de)serialization. */
         private static final long serialVersionUID = 8605517892232632586L;
 
-        /** Creates a new expression for the {@value #NAME} operation. */
+        /** Creates a new filter for the {@value #NAME} operation. */
         GreaterThan(Expression expression1, Expression expression2, boolean isMatchingCase, MatchAction matchAction) {
             super(expression1, expression2, isMatchingCase, matchAction);
         }
@@ -600,7 +600,7 @@ abstract class ComparisonFunction extends BinaryFunction implements BinaryCompar
         @Override protected boolean compare      (ChronoLocalDateTime<?> left, ChronoLocalDateTime<?> right) {return left.isAfter(right);}
         @Override protected boolean compare      (ChronoZonedDateTime<?> left, ChronoZonedDateTime<?> right) {return left.isAfter(right);}
 
-        /** Implementation of the visitor pattern. */
+        /** Implementation of the visitor pattern (not used by Apache SIS). */
         @Override public Object accept(FilterVisitor visitor, Object extraData) {
             return visitor.visit(this, extraData);
         }
@@ -608,13 +608,13 @@ abstract class ComparisonFunction extends BinaryFunction implements BinaryCompar
 
 
     /**
-     * The "GreaterThanOrEqualTo" (≥) expression.
+     * The {@value #NAME} (≥) filter.
      */
     static final class GreaterThanOrEqualTo extends ComparisonFunction implements org.opengis.filter.PropertyIsGreaterThanOrEqualTo {
-        /** For cross-version compatibility. */
+        /** For cross-version compatibility during (de)serialization. */
         private static final long serialVersionUID = 1514185657159141882L;
 
-        /** Creates a new expression for the {@value #NAME} operation. */
+        /** Creates a new filter for the {@value #NAME} operation. */
         GreaterThanOrEqualTo(Expression expression1, Expression expression2, boolean isMatchingCase, MatchAction matchAction) {
             super(expression1, expression2, isMatchingCase, matchAction);
         }
@@ -635,7 +635,7 @@ abstract class ComparisonFunction extends BinaryFunction implements BinaryCompar
         @Override protected boolean compare      (ChronoLocalDateTime<?> left, ChronoLocalDateTime<?> right) {return !left.isBefore(right);}
         @Override protected boolean compare      (ChronoZonedDateTime<?> left, ChronoZonedDateTime<?> right) {return !left.isBefore(right);}
 
-        /** Implementation of the visitor pattern. */
+        /** Implementation of the visitor pattern (not used by Apache SIS). */
         @Override public Object accept(FilterVisitor visitor, Object extraData) {
             return visitor.visit(this, extraData);
         }
@@ -643,13 +643,13 @@ abstract class ComparisonFunction extends BinaryFunction implements BinaryCompar
 
 
     /**
-     * The "EqualTo" (=) expression.
+     * The {@value #NAME} (=) filter.
      */
     static final class EqualTo extends ComparisonFunction implements org.opengis.filter.PropertyIsEqualTo {
-        /** For cross-version compatibility. */
+        /** For cross-version compatibility during (de)serialization. */
         private static final long serialVersionUID = 8502612221498749667L;
 
-        /** Creates a new expression for the {@value #NAME} operation. */
+        /** Creates a new filter for the {@value #NAME} operation. */
         EqualTo(Expression expression1, Expression expression2, boolean isMatchingCase, MatchAction matchAction) {
             super(expression1, expression2, isMatchingCase, matchAction);
         }
@@ -670,7 +670,7 @@ abstract class ComparisonFunction extends BinaryFunction implements BinaryCompar
         @Override protected boolean compare      (ChronoLocalDateTime<?> left, ChronoLocalDateTime<?> right) {return left.isEqual(right);}
         @Override protected boolean compare      (ChronoZonedDateTime<?> left, ChronoZonedDateTime<?> right) {return left.isEqual(right);}
 
-        /** Implementation of the visitor pattern. */
+        /** Implementation of the visitor pattern (not used by Apache SIS). */
         @Override public Object accept(FilterVisitor visitor, Object extraData) {
             return visitor.visit(this, extraData);
         }
@@ -678,13 +678,13 @@ abstract class ComparisonFunction extends BinaryFunction implements BinaryCompar
 
 
     /**
-     * The "NotEqualTo" (≠) expression.
+     * The {@value #NAME} (≠) filter.
      */
     static final class NotEqualTo extends ComparisonFunction implements org.opengis.filter.PropertyIsNotEqualTo {
-        /** For cross-version compatibility. */
+        /** For cross-version compatibility during (de)serialization. */
         private static final long serialVersionUID = -3295957142249035362L;
 
-        /** Creates a new expression for the {@value #NAME} operation. */
+        /** Creates a new filter for the {@value #NAME} operation. */
         NotEqualTo(Expression expression1, Expression expression2, boolean isMatchingCase, MatchAction matchAction) {
             super(expression1, expression2, isMatchingCase, matchAction);
         }
@@ -705,7 +705,7 @@ abstract class ComparisonFunction extends BinaryFunction implements BinaryCompar
         @Override protected boolean compare      (ChronoLocalDateTime<?> left, ChronoLocalDateTime<?> right) {return !left.isEqual(right);}
         @Override protected boolean compare      (ChronoZonedDateTime<?> left, ChronoZonedDateTime<?> right) {return !left.isEqual(right);}
 
-        /** Implementation of the visitor pattern. */
+        /** Implementation of the visitor pattern (not used by Apache SIS). */
         @Override public Object accept(FilterVisitor visitor, Object extraData) {
             return visitor.visit(this, extraData);
         }
diff --git a/core/sis-feature/src/main/java/org/apache/sis/filter/DefaultFilterFactory.java b/core/sis-feature/src/main/java/org/apache/sis/filter/DefaultFilterFactory.java
index ea6422d..94a1cb4 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/filter/DefaultFilterFactory.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/filter/DefaultFilterFactory.java
@@ -652,7 +652,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
      */
     @Override
     public TContains tcontains(Expression expression1, Expression expression2) {
-        return new TemporalFunction.TContains(expression1, expression2);
+        return new TemporalFunction.Contains(expression1, expression2);
     }
 
     /**
@@ -660,7 +660,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
      */
     @Override
     public TEquals tequals(Expression expression1, Expression expression2) {
-        return new TemporalFunction.TEquals(expression1, expression2);
+        return new TemporalFunction.Equals(expression1, expression2);
     }
 
     /**
@@ -668,7 +668,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
      */
     @Override
     public TOverlaps toverlaps(Expression expression1, Expression expression2) {
-        return new TemporalFunction.TOverlaps(expression1, expression2);
+        return new TemporalFunction.Overlaps(expression1, expression2);
     }
 
     // EXPRESSIONS /////////////////////////////////////////////////////////////
diff --git a/core/sis-feature/src/main/java/org/apache/sis/filter/TemporalFunction.java b/core/sis-feature/src/main/java/org/apache/sis/filter/TemporalFunction.java
index 394f1c8..4aef3b1 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/filter/TemporalFunction.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/filter/TemporalFunction.java
@@ -16,15 +16,28 @@
  */
 package org.apache.sis.filter;
 
-import org.apache.sis.util.ArgumentChecks;
-import org.opengis.filter.Filter;
+import java.util.Date;
+import java.time.Instant;
+import java.math.BigDecimal;
+import java.math.BigInteger;
 import org.opengis.filter.FilterVisitor;
 import org.opengis.filter.expression.Expression;
+import org.opengis.filter.temporal.BinaryTemporalOperator;
+import org.opengis.temporal.Period;
+import org.apache.sis.math.Fraction;
+
 
 
 /**
- * Temporal operations between two time values.
+ * Temporal operations between a period and an instant.
  * The nature of the operation depends on the subclass.
+ * Subclasses shall override at least one of following methods:
+ *
+ * <ul>
+ *   <li>{@link #evaluate(Instant, Instant)}</li>
+ *   <li>{@link #evaluate(Period, Instant)}</li>
+ *   <li>{@link #evaluate(Period, Period)}</li>
+ * </ul>
  *
  * @author  Johann Sorel (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
@@ -32,340 +45,676 @@ import org.opengis.filter.expression.Expression;
  * @since   1.0
  * @module
  */
-abstract class TemporalFunction implements Filter {
+abstract class TemporalFunction extends BinaryFunction implements BinaryTemporalOperator {
+    /**
+     * For cross-version compatibility.
+     */
+    private static final long serialVersionUID = 5392780837658687513L;
 
     /**
-     * The first of the two expressions to be used by this function.
+     * Creates a new temporal function.
      *
-     * @see #getExpression1()
+     * @param  expression1  the first of the two expressions to be used by this function.
+     * @param  expression2  the second of the two expressions to be used by this function.
      */
-    protected final Expression expression1;
+    TemporalFunction(final Expression expression1, final Expression expression2) {
+        super(expression1, expression2);
+    }
 
     /**
-     * The second of the two expressions to be used by this function.
+     * Converts a GeoAPI instant to a Java instant. This is a temporary method
+     * to be removed after we revisited {@link org.opengis.temporal} package.
      *
-     * @see #getExpression2()
+     * @param  instant  the GeoAPI instant, or {@code null}.
+     * @return the Java instant, or {@code null}.
      */
-    protected final Expression expression2;
+    private static Instant toInstant(final org.opengis.temporal.Instant instant) {
+        if (instant != null) {
+            final Date t = instant.getDate();
+            if (t != null) {
+                return t.toInstant();
+            }
+        }
+        return null;
+    }
 
     /**
-     * Creates a new temporal function.
-     *
-     * @param  expression1  the first of the two expressions to be used by this function.
-     * @param  expression2  the second of the two expressions to be used by this function.
+     * Returns {@code true} if {@code self} is non null and before {@code other}.
+     * This is an helper function for {@code evaluate(…)} methods implementations.
      */
-    TemporalFunction(final Expression expression1, final Expression expression2) {
-        ArgumentChecks.ensureNonNull("expression1", expression1);
-        ArgumentChecks.ensureNonNull("expression2", expression2);
-        this.expression1 = expression1;
-        this.expression2 = expression2;
+    private static boolean isBefore(final org.opengis.temporal.Instant self, final Instant other) {
+        final Instant t = toInstant(self);
+        return (t != null) && t.isBefore(other);
     }
 
     /**
-     * Returns the first of the two expressions to be used by this function.
-     * This is the value specified at construction time.
+     * Returns {@code true} if {@code self} is non null and after {@code other}.
+     * This is an helper function for {@code evaluate(…)} methods implementations.
      */
-    public final Expression getExpression1() {
-        return expression1;
+    private static boolean isAfter(final org.opengis.temporal.Instant self, final Instant other) {
+        final Instant t = toInstant(self);
+        return (t != null) && t.isAfter(other);
     }
 
     /**
-     * Returns the second of the two expressions to be used by this function.
-     * This is the value specified at construction time.
+     * Returns {@code true} if {@code self} is non null and equal to {@code other}.
+     * This is an helper function for {@code evaluate(…)} methods implementations.
      */
-    public final Expression getExpression2() {
-        return expression2;
+    private static boolean isEqual(final org.opengis.temporal.Instant self, final Instant other) {
+        final Instant t = toInstant(self);
+        return (t != null) && t.equals(other);
     }
 
     /**
-     * The "After" filter.
+     * Returns {@code true} if {@code self} is non null and before {@code other}.
+     * This is an helper function for {@code evaluate(…)} methods implementations.
      */
-    static final class After extends TemporalFunction implements org.opengis.filter.temporal.After {
+    private static boolean isBefore(final org.opengis.temporal.Instant self,
+                                    final org.opengis.temporal.Instant other)
+    {
+        final Instant t, o;
+        return ((t = toInstant(self)) != null) && ((o = toInstant(other)) != null) && t.isBefore(o);
+    }
 
-        /** Creates a new expression for the {@value #NAME} operation. */
-        After(Expression expression1, Expression expression2) {
+    /**
+     * Returns {@code true} if {@code self} is non null and after {@code other}.
+     * This is an helper function for {@code evaluate(…)} methods implementations.
+     */
+    private static boolean isAfter(final org.opengis.temporal.Instant self,
+                                   final org.opengis.temporal.Instant other)
+    {
+        final Instant t, o;
+        return ((t = toInstant(self)) != null) && ((o = toInstant(other)) != null) && t.isAfter(o);
+    }
+
+    /**
+     * Returns {@code true} if {@code self} is non null and equal to {@code other}.
+     * This is an helper function for {@code evaluate(…)} methods implementations.
+     */
+    private static boolean isEqual(final org.opengis.temporal.Instant self,
+                                   final org.opengis.temporal.Instant other)
+    {
+        final Instant t = toInstant(self);
+        return (t != null) && t.equals(toInstant(other));
+    }
+
+    /**
+     * Determines if the test(s) represented by this filter passes with the given operands.
+     * Values of {@link #expression1} and {@link #expression2} shall be two single values.
+     */
+    @Override
+    public final boolean evaluate(final Object candidate) {
+        final Object left = expression1.evaluate(candidate);
+        if (left instanceof Period) {
+            final Object right = expression2.evaluate(candidate);
+            if (right instanceof Period) {
+                return evaluate((Period) left, (Period) right);
+            }
+            final Instant t = ComparisonFunction.toInstant(right);
+            if (t != null) {
+                return evaluate((Period) left, t);
+            }
+        } else {
+            final Instant t = ComparisonFunction.toInstant(left);
+            if (t != null) {
+                final Instant t2 = ComparisonFunction.toInstant(expression2.evaluate(candidate));
+                if (t2 != null) {
+                    return evaluate(t, t2);
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Evaluates the filter between two instants.
+     * Both arguments given to this method are non-null.
+     * The {@code self} and {@code other} argument names are chosen to match ISO 19108 tables.
+     */
+    protected boolean evaluate(Instant self, Instant other) {
+        return false;
+    }
+
+    /**
+     * Evaluates the filter between a period and an instant.
+     * Both arguments given to this method are non-null, but period begin or end instant may be null.
+     * The {@code self} and {@code other} argument names are chosen to match ISO 19108 tables.
+     */
+    protected boolean evaluate(Period self, Instant other) {
+        return false;
+    }
+
+    /**
+     * Evaluates the filter between two periods.
+     * Both arguments given to this method are non-null, but period begin or end instant may be null.
+     * The {@code self} and {@code other} argument names are chosen to match ISO 19108 tables.
+     */
+    protected boolean evaluate(Period self, Period other) {
+        return false;
+    }
+
+    /**
+     * No operation on numbers for now. We could revisit this policy in a future version if we
+     * allow the temporal function to have a CRS and to operate on temporal coordinate values.
+     */
+    @Override protected Number applyAsLong    (long       left, long       right) {return null;}
+    @Override protected Number applyAsDouble  (double     left, double     right) {return null;}
+    @Override protected Number applyAsFraction(Fraction   left, Fraction   right) {return null;}
+    @Override protected Number applyAsInteger (BigInteger left, BigInteger right) {return null;}
+    @Override protected Number applyAsDecimal (BigDecimal left, BigDecimal right) {return null;}
+
+
+    /**
+     * The {@value #NAME} (=) filter. Defined by ISO 19108 as:
+     * <ul>
+     *   <li>{@literal self = other}</li>
+     *   <li>{@literal self.begin = other.begin  AND  self.end = other.end}</li>
+     * </ul>
+     */
+    static final class Equals extends TemporalFunction implements org.opengis.filter.temporal.TEquals {
+        /** For cross-version compatibility during (de)serialization. */
+        private static final long serialVersionUID = -6060822291802339424L;
+
+        /** Creates a new filter for the {@value #NAME} operation. */
+        Equals(Expression expression1, Expression expression2) {
             super(expression1, expression2);
         }
 
-        @Override
-        public boolean evaluate(Object object) {
-            throw new UnsupportedOperationException("Not supported yet.");
+        /** Identification of this operation. */
+        @Override protected String getName() {return NAME;}
+        @Override protected char   symbol()  {return '=';}
+
+        /** Condition defined by ISO 19108:2002 §5.2.3.5. */
+        @Override protected boolean evaluate(final Instant self, final Instant other) {
+            return self.equals(other);
+        }
+
+        /** Extension to ISO 19108: handle instant as a tiny period. */
+        @Override public boolean evaluate(final Period self, final Instant other) {
+            return isEqual(self.getBeginning(), other) &&
+                   isEqual(self.getEnding(),    other);
         }
 
-        /** Implementation of the visitor pattern. */
+        /** Condition defined by ISO 19108:2006 (corrigendum) §5.2.3.5. */
+        @Override public boolean evaluate(final Period self, final Period other) {
+            return isEqual(self.getBeginning(), other.getBeginning()) &&
+                   isEqual(self.getEnding(),    other.getEnding());
+        }
+
+        /** Implementation of the visitor pattern (not used by Apache SIS). */
         @Override public Object accept(FilterVisitor visitor, Object extraData) {
             return visitor.visit(this, extraData);
         }
     }
 
+
     /**
-     * The "AnyInteracts" filter.
+     * The {@value #NAME} {@literal (<)} filter. Defined by ISO 19108 as:
+     * <ul>
+     *   <li>{@literal self     < other}</li>
+     *   <li>{@literal self.end < other}</li>
+     *   <li>{@literal self.end < other.begin}</li>
+     * </ul>
      */
-    static final class AnyInteracts extends TemporalFunction implements org.opengis.filter.temporal.AnyInteracts {
+    static final class Before extends TemporalFunction implements org.opengis.filter.temporal.Before {
+        /** For cross-version compatibility during (de)serialization. */
+        private static final long serialVersionUID = -3422629447456003982L;
 
-        /** Creates a new expression for the {@value #NAME} operation. */
-        AnyInteracts(Expression expression1, Expression expression2) {
+        /** Creates a new filter for the {@value #NAME} operation. */
+        Before(Expression expression1, Expression expression2) {
             super(expression1, expression2);
         }
 
-        @Override
-        public boolean evaluate(Object object) {
-            throw new UnsupportedOperationException("Not supported yet.");
+        /** Identification of this operation. */
+        @Override protected String getName() {return NAME;}
+        @Override protected char   symbol()  {return '<';}
+
+        /** Condition defined by ISO 19108:2002 §5.2.3.5. */
+        @Override protected boolean evaluate(final Instant self, final Instant other) {
+            return self.isBefore(other);
         }
 
-        /** Implementation of the visitor pattern. */
+        /** Condition defined by ISO 19108:2006 (corrigendum) §5.2.3.5. */
+        @Override public boolean evaluate(final Period self, final Instant other) {
+            return isBefore(self.getEnding(), other);
+        }
+
+        /** Condition defined by ISO 19108:2006 (corrigendum) §5.2.3.5. */
+        @Override public boolean evaluate(final Period self, final Period other) {
+            return isBefore(self.getEnding(), other.getBeginning());
+        }
+
+        /** Implementation of the visitor pattern (not used by Apache SIS). */
         @Override public Object accept(FilterVisitor visitor, Object extraData) {
             return visitor.visit(this, extraData);
         }
     }
 
+
     /**
-     * The "Before" filter.
+     * The {@value #NAME} {@literal (>)} filter. Defined by ISO 19108 as:
+     * <ul>
+     *   <li>{@literal self       > other}</li>
+     *   <li>{@literal self.begin > other}</li>
+     *   <li>{@literal self.begin > other.end}</li>
+     * </ul>
      */
-    static final class Before extends TemporalFunction implements org.opengis.filter.temporal.Before {
+    static final class After extends TemporalFunction implements org.opengis.filter.temporal.After {
+        /** For cross-version compatibility during (de)serialization. */
+        private static final long serialVersionUID = 5410476260417497682L;
 
-        /** Creates a new expression for the {@value #NAME} operation. */
-        Before(Expression expression1, Expression expression2) {
+        /** Creates a new filter for the {@value #NAME} operation. */
+        After(Expression expression1, Expression expression2) {
             super(expression1, expression2);
         }
 
-        @Override
-        public boolean evaluate(Object object) {
-            throw new UnsupportedOperationException("Not supported yet.");
+        /** Identification of this operation. */
+        @Override protected String getName() {return NAME;}
+        @Override protected char   symbol()  {return '>';}
+
+        /** Condition defined by ISO 19108:2002 §5.2.3.5. */
+        @Override protected boolean evaluate(final Instant self, final Instant other) {
+            return self.isAfter(other);
+        }
+
+        /** Condition defined by ISO 19108:2006 (corrigendum) §5.2.3.5. */
+        @Override public boolean evaluate(final Period self, final Instant other) {
+            return isAfter(self.getBeginning(), other);
+        }
+
+        /** Condition defined by ISO 19108:2006 (corrigendum) §5.2.3.5. */
+        @Override public boolean evaluate(final Period self, final Period other) {
+            return isAfter(self.getBeginning(), other.getEnding());
         }
 
-        /** Implementation of the visitor pattern. */
+        /** Implementation of the visitor pattern (not used by Apache SIS). */
         @Override public Object accept(FilterVisitor visitor, Object extraData) {
             return visitor.visit(this, extraData);
         }
     }
 
+
     /**
-     * The "Begins" filter.
+     * The {@value #NAME} filter. Defined by ISO 19108 as:
+     * <ul>
+     *   <li>{@literal self.begin = other.begin  AND  self.end < other.end}</li>
+     * </ul>
      */
     static final class Begins extends TemporalFunction implements org.opengis.filter.temporal.Begins {
+        /** For cross-version compatibility during (de)serialization. */
+        private static final long serialVersionUID = -7880699329127762233L;
 
-        /** Creates a new expression for the {@value #NAME} operation. */
+        /** Creates a new filter for the {@value #NAME} operation. */
         Begins(Expression expression1, Expression expression2) {
             super(expression1, expression2);
         }
 
-        @Override
-        public boolean evaluate(Object object) {
-            throw new UnsupportedOperationException("Not supported yet.");
+        /** Identification of this operation. */
+        @Override protected String getName() {return NAME;}
+
+        /** Condition defined by ISO 19108:2006 (corrigendum) §5.2.3.5. */
+        @Override public boolean evaluate(final Period self, final Period other) {
+            return isEqual (self.getBeginning(), other.getBeginning()) &&
+                   isBefore(self.getEnding(),    other.getEnding());
         }
 
-        /** Implementation of the visitor pattern. */
+        /** Implementation of the visitor pattern (not used by Apache SIS). */
         @Override public Object accept(FilterVisitor visitor, Object extraData) {
             return visitor.visit(this, extraData);
         }
     }
 
+
     /**
-     * The "BegunBy" filter.
+     * The {@value #NAME} filter. Defined by ISO 19108 as:
+     * <ul>
+     *   <li>{@literal self.begin > other.begin  AND  self.end = other.end}</li>
+     * </ul>
      */
-    static final class BegunBy extends TemporalFunction implements org.opengis.filter.temporal.BegunBy {
+    static final class Ends extends TemporalFunction implements org.opengis.filter.temporal.Ends {
+        /** For cross-version compatibility during (de)serialization. */
+        private static final long serialVersionUID = -5508229966320563437L;
 
-        /** Creates a new expression for the {@value #NAME} operation. */
-        BegunBy(Expression expression1, Expression expression2) {
+        /** Creates a new filter for the {@value #NAME} operation. */
+        Ends(Expression expression1, Expression expression2) {
             super(expression1, expression2);
         }
 
-        @Override
-        public boolean evaluate(Object object) {
-            throw new UnsupportedOperationException("Not supported yet.");
+        /** Identification of this operation. */
+        @Override protected String getName() {return NAME;}
+
+        /** Condition defined by ISO 19108:2006 (corrigendum) §5.2.3.5. */
+        @Override public boolean evaluate(final Period self, final Period other) {
+            return isEqual(self.getEnding(),    other.getEnding()) &&
+                   isAfter(self.getBeginning(), other.getBeginning());
         }
 
-        /** Implementation of the visitor pattern. */
+        /** Implementation of the visitor pattern (not used by Apache SIS). */
         @Override public Object accept(FilterVisitor visitor, Object extraData) {
             return visitor.visit(this, extraData);
         }
     }
 
+
     /**
-     * The "During" filter.
+     * The {@value #NAME} filter. Defined by ISO 19108 as:
+     * <ul>
+     *   <li>{@literal self.begin = other}</li>
+     *   <li>{@literal self.begin = other.begin  AND  self.end > other.end}</li>
+     * </ul>
      */
-    static final class During extends TemporalFunction implements org.opengis.filter.temporal.During {
+    static final class BegunBy extends TemporalFunction implements org.opengis.filter.temporal.BegunBy {
+        /** For cross-version compatibility during (de)serialization. */
+        private static final long serialVersionUID = -7212413827394364384L;
 
-        /** Creates a new expression for the {@value #NAME} operation. */
-        During(Expression expression1, Expression expression2) {
+        /** Creates a new filter for the {@value #NAME} operation. */
+        BegunBy(Expression expression1, Expression expression2) {
             super(expression1, expression2);
         }
 
-        @Override
-        public boolean evaluate(Object object) {
-            throw new UnsupportedOperationException("Not supported yet.");
+        /** Identification of this operation. */
+        @Override protected String getName() {return NAME;}
+
+        /** Condition defined by ISO 19108:2006 (corrigendum) §5.2.3.5. */
+        @Override public boolean evaluate(final Period self, final Instant other) {
+            return isEqual(self.getBeginning(), other);
+        }
+
+        /** Condition defined by ISO 19108:2006 (corrigendum) §5.2.3.5. */
+        @Override public boolean evaluate(final Period self, final Period other) {
+            return isEqual(self.getBeginning(), other.getBeginning()) &&
+                   isAfter(self.getEnding(),    other.getEnding());
         }
 
-        /** Implementation of the visitor pattern. */
+        /** Implementation of the visitor pattern (not used by Apache SIS). */
         @Override public Object accept(FilterVisitor visitor, Object extraData) {
             return visitor.visit(this, extraData);
         }
     }
 
+
     /**
-     * The "EndedBy" filter.
+     * The {@value #NAME} filter. Defined by ISO 19108 as:
+     * <ul>
+     *   <li>{@literal self.end = other}</li>
+     *   <li>{@literal self.begin < other.begin  AND  self.end = other.end}</li>
+     * </ul>
      */
     static final class EndedBy extends TemporalFunction implements org.opengis.filter.temporal.EndedBy {
+        /** For cross-version compatibility during (de)serialization. */
+        private static final long serialVersionUID = 8586566103462153666L;
 
-        /** Creates a new expression for the {@value #NAME} operation. */
+        /** Creates a new filter for the {@value #NAME} operation. */
         EndedBy(Expression expression1, Expression expression2) {
             super(expression1, expression2);
         }
 
-        @Override
-        public boolean evaluate(Object object) {
-            throw new UnsupportedOperationException("Not supported yet.");
+        /** Identification of this operation. */
+        @Override protected String getName() {return NAME;}
+
+        /** Condition defined by ISO 19108:2006 (corrigendum) §5.2.3.5. */
+        @Override public boolean evaluate(final Period self, final Instant other) {
+            return isEqual(self.getEnding(), other);
         }
 
-        /** Implementation of the visitor pattern. */
+        /** Condition defined by ISO 19108:2006 (corrigendum) §5.2.3.5. */
+        @Override public boolean evaluate(final Period self, final Period other) {
+            return isEqual (self.getEnding(),    other.getEnding()) &&
+                   isBefore(self.getBeginning(), other.getBeginning());
+        }
+
+        /** Implementation of the visitor pattern (not used by Apache SIS). */
         @Override public Object accept(FilterVisitor visitor, Object extraData) {
             return visitor.visit(this, extraData);
         }
     }
 
+
     /**
-     * The "Ends" filter.
+     * The {@value #NAME} filter. Defined by ISO 19108 as:
+     * <ul>
+     *   <li>{@literal self.end = other.begin}</li>
+     * </ul>
      */
-    static final class Ends extends TemporalFunction implements org.opengis.filter.temporal.Ends {
+    static final class Meets extends TemporalFunction implements org.opengis.filter.temporal.Meets {
+        /** For cross-version compatibility during (de)serialization. */
+        private static final long serialVersionUID = -3534843269384858443L;
 
-        /** Creates a new expression for the {@value #NAME} operation. */
-        Ends(Expression expression1, Expression expression2) {
+        /** Creates a new filter for the {@value #NAME} operation. */
+        Meets(Expression expression1, Expression expression2) {
             super(expression1, expression2);
         }
 
-        @Override
-        public boolean evaluate(Object object) {
-            throw new UnsupportedOperationException("Not supported yet.");
+        /** Identification of this operation. */
+        @Override protected String getName() {return NAME;}
+
+        /** Extension to ISO 19108: handle instant as a tiny period. */
+        @Override public boolean evaluate(final Instant self, final Instant other) {
+            return self.equals(other);
+        }
+
+        /** Extension to ISO 19108: handle instant as a tiny period. */
+        @Override public boolean evaluate(final Period self, final Instant other) {
+            return isEqual(self.getEnding(), other);
+        }
+
+        /** Condition defined by ISO 19108:2006 (corrigendum) §5.2.3.5. */
+        @Override public boolean evaluate(final Period self, final Period other) {
+            return isEqual(self.getEnding(), other.getBeginning());
         }
 
-        /** Implementation of the visitor pattern. */
+        /** Implementation of the visitor pattern (not used by Apache SIS). */
         @Override public Object accept(FilterVisitor visitor, Object extraData) {
             return visitor.visit(this, extraData);
         }
     }
 
+
     /**
-     * The "Meets" filter.
+     * The {@value #NAME} filter. Defined by ISO 19108 as:
+     * <ul>
+     *   <li>{@literal self.begin = other.end}</li>
+     * </ul>
      */
-    static final class Meets extends TemporalFunction implements org.opengis.filter.temporal.Meets {
+    static final class MetBy extends TemporalFunction implements org.opengis.filter.temporal.MetBy {
+        /** For cross-version compatibility during (de)serialization. */
+        private static final long serialVersionUID = 5358059498707330482L;
 
-        /** Creates a new expression for the {@value #NAME} operation. */
-        Meets(Expression expression1, Expression expression2) {
+        /** Creates a new filter for the {@value #NAME} operation. */
+        MetBy(Expression expression1, Expression expression2) {
             super(expression1, expression2);
         }
 
-        @Override
-        public boolean evaluate(Object object) {
-            throw new UnsupportedOperationException("Not supported yet.");
+        /** Identification of this operation. */
+        @Override protected String getName() {return NAME;}
+
+        /** Extension to ISO 19108: handle instant as a tiny period. */
+        @Override public boolean evaluate(final Instant self, final Instant other) {
+            return self.equals(other);
+        }
+
+        /** Extension to ISO 19108: handle instant as a tiny period. */
+        @Override public boolean evaluate(final Period self, final Instant other) {
+            return isEqual(self.getBeginning(), other);
         }
 
-        /** Implementation of the visitor pattern. */
+        /** Condition defined by ISO 19108:2006 (corrigendum) §5.2.3.5. */
+        @Override public boolean evaluate(final Period self, final Period other) {
+            return isEqual(self.getBeginning(), other.getEnding());
+        }
+
+        /** Implementation of the visitor pattern (not used by Apache SIS). */
         @Override public Object accept(FilterVisitor visitor, Object extraData) {
             return visitor.visit(this, extraData);
         }
     }
 
+
     /**
-     * The "MetBy" filter.
+     * The {@value #NAME} filter. Defined by ISO 19108 as:
+     * <ul>
+     *   <li>{@literal self.begin > other.begin  AND  self.end < other.end}</li>
+     * </ul>
      */
-    static final class MetBy extends TemporalFunction implements org.opengis.filter.temporal.MetBy {
+    static final class During extends TemporalFunction implements org.opengis.filter.temporal.During {
+        /** For cross-version compatibility during (de)serialization. */
+        private static final long serialVersionUID = -4674319635076886196L;
 
-        /** Creates a new expression for the {@value #NAME} operation. */
-        MetBy(Expression expression1, Expression expression2) {
+        /** Creates a new filter for the {@value #NAME} operation. */
+        During(Expression expression1, Expression expression2) {
             super(expression1, expression2);
         }
 
-        @Override
-        public boolean evaluate(Object object) {
-            throw new UnsupportedOperationException("Not supported yet.");
+        /** Identification of this operation. */
+        @Override protected String getName() {return NAME;}
+        @Override protected char   symbol()  {return '⊊';}      // `self` is a proper (or strict) subset of `other`.
+
+        /** Condition defined by ISO 19108:2006 (corrigendum) §5.2.3.5. */
+        @Override public boolean evaluate(final Period self, final Period other) {
+            return isAfter (self.getBeginning(), other.getBeginning()) &&
+                   isBefore(self.getEnding(),    other.getEnding());
         }
 
-        /** Implementation of the visitor pattern. */
+        /** Implementation of the visitor pattern (not used by Apache SIS). */
         @Override public Object accept(FilterVisitor visitor, Object extraData) {
             return visitor.visit(this, extraData);
         }
     }
 
+
     /**
-     * The "OverlappedBy" filter.
+     * The {@value #NAME} filter. Defined by ISO 19108 as:
+     * <ul>
+     *   <li>{@literal self.begin < other AND self.end > other}</li>
+     *   <li>{@literal self.begin < other.begin  AND  self.end > other.end}</li>
+     * </ul>
      */
-    static final class OverlappedBy extends TemporalFunction implements org.opengis.filter.temporal.OverlappedBy {
+    static final class Contains extends TemporalFunction implements org.opengis.filter.temporal.TContains {
+        /** For cross-version compatibility during (de)serialization. */
+        private static final long serialVersionUID = 9107531246948034411L;
 
-        /** Creates a new expression for the {@value #NAME} operation. */
-        OverlappedBy(Expression expression1, Expression expression2) {
+        /** Creates a new filter for the {@value #NAME} operation. */
+        Contains(Expression expression1, Expression expression2) {
             super(expression1, expression2);
         }
 
-        @Override
-        public boolean evaluate(Object object) {
-            throw new UnsupportedOperationException("Not supported yet.");
+        /** Identification of this operation. */
+        @Override protected String getName() {return NAME;}
+        @Override protected char   symbol()  {return '⊋';}      // `self` is a proper (or strict) superset of `other`.
+
+        /** Condition defined by ISO 19108:2006 (corrigendum) §5.2.3.5. */
+        @Override public boolean evaluate(final Period self, final Instant other) {
+            return isBefore(self.getBeginning(), other) &&
+                   isAfter (self.getEnding(),    other);
+        }
+
+        /** Condition defined by ISO 19108:2006 (corrigendum) §5.2.3.5. */
+        @Override public boolean evaluate(final Period self, final Period other) {
+            return isBefore(self.getBeginning(), other.getBeginning()) &&
+                   isAfter (self.getEnding(),    other.getEnding());
         }
 
-        /** Implementation of the visitor pattern. */
+        /** Implementation of the visitor pattern (not used by Apache SIS). */
         @Override public Object accept(FilterVisitor visitor, Object extraData) {
             return visitor.visit(this, extraData);
         }
     }
 
+
     /**
-     * The "TContains" filter.
+     * The {@value #NAME} filter. Defined by ISO 19108 as:
+     * <ul>
+     *   <li>{@literal self.begin < other.begin  AND  self.end > other.begin  AND  self.end < other.end}</li>
+     * </ul>
      */
-    static final class TContains extends TemporalFunction implements org.opengis.filter.temporal.TContains {
+    static final class Overlaps extends TemporalFunction implements org.opengis.filter.temporal.TOverlaps {
+        /** For cross-version compatibility during (de)serialization. */
+        private static final long serialVersionUID = 1517443045593389773L;
 
-        /** Creates a new expression for the {@value #NAME} operation. */
-        TContains(Expression expression1, Expression expression2) {
+        /** Creates a new filter for the {@value #NAME} operation. */
+        Overlaps(Expression expression1, Expression expression2) {
             super(expression1, expression2);
         }
 
-        @Override
-        public boolean evaluate(Object object) {
-            throw new UnsupportedOperationException("Not supported yet.");
+        /** Identification of this operation. */
+        @Override protected String getName() {return NAME;}
+
+        /** Condition defined by ISO 19108:2006 (corrigendum) §5.2.3.5. */
+        @Override public boolean evaluate(final Period self, final Period other) {
+            final Instant selfEnd, otherBegin;
+            return ((selfEnd    = toInstant(self .getEnding()))    != null) &&
+                   ((otherBegin = toInstant(other.getBeginning())) != null) && selfEnd.isAfter(otherBegin) &&
+                   isBefore(self.getBeginning(), otherBegin) &&
+                   isAfter(other.getEnding(),    selfEnd);
         }
 
-        /** Implementation of the visitor pattern. */
+        /** Implementation of the visitor pattern (not used by Apache SIS). */
         @Override public Object accept(FilterVisitor visitor, Object extraData) {
             return visitor.visit(this, extraData);
         }
     }
 
+
     /**
-     * The "TEquals" filter.
+     * The {@value #NAME} filter. Defined by ISO 19108 as:
+     * <ul>
+     *   <li>{@literal self.begin > other.begin  AND  self.begin < other.end  AND  self.end > other.end}</li>
+     * </ul>
      */
-    static final class TEquals extends TemporalFunction implements org.opengis.filter.temporal.TEquals {
+    static final class OverlappedBy extends TemporalFunction implements org.opengis.filter.temporal.OverlappedBy {
+        /** For cross-version compatibility during (de)serialization. */
+        private static final long serialVersionUID = 2228673820507226463L;
 
-        /** Creates a new expression for the {@value #NAME} operation. */
-        TEquals(Expression expression1, Expression expression2) {
+        /** Creates a new filter for the {@value #NAME} operation. */
+        OverlappedBy(Expression expression1, Expression expression2) {
             super(expression1, expression2);
         }
 
-        @Override
-        public boolean evaluate(Object object) {
-            throw new UnsupportedOperationException("Not supported yet.");
-        }
+        /** Identification of this operation. */
+        @Override protected String getName() {return NAME;}
 
-        /** Implementation of the visitor pattern. */
+        /** Implementation of the visitor pattern (not used by Apache SIS). */
         @Override public Object accept(FilterVisitor visitor, Object extraData) {
             return visitor.visit(this, extraData);
         }
+
+        /** Condition defined by ISO 19108:2006 (corrigendum) §5.2.3.5. */
+        @Override public boolean evaluate(final Period self, final Period other) {
+            final Instant selfBegin, otherEnd;
+            return ((selfBegin = toInstant(self .getBeginning())) != null) &&
+                   ((otherEnd  = toInstant(other.getEnding()))    != null) && selfBegin.isBefore(otherEnd) &&
+                   isBefore(other.getBeginning(), selfBegin) &&
+                   isAfter (self .getEnding(),    otherEnd);
+        }
     }
 
+
     /**
-     * The "TOverlaps" filter.
+     * The {@value #NAME} filter.
+     * This is a shortcut for NOT (Before OR Meets OR MetBy OR After).
      */
-    static final class TOverlaps extends TemporalFunction implements org.opengis.filter.temporal.TOverlaps {
+    static final class AnyInteracts extends TemporalFunction implements org.opengis.filter.temporal.AnyInteracts {
+        /** For cross-version compatibility during (de)serialization. */
+        private static final long serialVersionUID = 5972351564286442392L;
 
-        /** Creates a new expression for the {@value #NAME} operation. */
-        TOverlaps(Expression expression1, Expression expression2) {
+        /** Creates a new filter for the {@value #NAME} operation. */
+        AnyInteracts(Expression expression1, Expression expression2) {
             super(expression1, expression2);
         }
 
-        @Override
-        public boolean evaluate(Object object) {
-            throw new UnsupportedOperationException("Not supported yet.");
+        /** Identification of this operation. */
+        @Override protected String getName() {return NAME;}
+
+        /** Condition defined by OGC filter specification. */
+        @Override public boolean evaluate(final Period self, final Period other) {
+            final Instant selfBegin, selfEnd, otherBegin, otherEnd;
+            return ((selfBegin  = toInstant(self .getBeginning())) != null) &&
+                   ((otherEnd   = toInstant(other.getEnding()))    != null) && selfBegin.isBefore(otherEnd) &&
+                   ((selfEnd    = toInstant(self .getEnding()))    != null) &&
+                   ((otherBegin = toInstant(other.getBeginning())) != null) && selfEnd.isAfter(otherBegin);
         }
 
-        /** Implementation of the visitor pattern. */
+        /** Implementation of the visitor pattern (not used by Apache SIS). */
         @Override public Object accept(FilterVisitor visitor, Object extraData) {
             return visitor.visit(this, extraData);
         }
diff --git a/core/sis-feature/src/test/java/org/apache/sis/filter/PeriodLiteral.java b/core/sis-feature/src/test/java/org/apache/sis/filter/PeriodLiteral.java
new file mode 100644
index 0000000..e626ff2
--- /dev/null
+++ b/core/sis-feature/src/test/java/org/apache/sis/filter/PeriodLiteral.java
@@ -0,0 +1,116 @@
+/*
+ * 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.sis.filter;
+
+import java.util.Date;
+import java.util.Objects;
+import java.io.Serializable;
+import org.opengis.temporal.Period;
+import org.opengis.temporal.Duration;
+import org.opengis.temporal.RelativePosition;
+import org.opengis.temporal.TemporalPosition;
+import org.opengis.temporal.TemporalPrimitive;
+import org.opengis.temporal.TemporalGeometricPrimitive;
+import org.opengis.filter.expression.Literal;
+import org.opengis.filter.expression.ExpressionVisitor;
+import org.opengis.metadata.Identifier;
+import org.apache.sis.test.TestUtilities;
+
+
+/**
+ * A literal expression which returns a period computed from {@link #begin} and {@link #end} fields.
+ * This is used for testing purpose only.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @version 1.0
+ * @since   1.0
+ * @module
+ */
+@SuppressWarnings("serial")
+final strictfp class PeriodLiteral implements Period, Literal, Serializable {
+    /**
+     * Period beginning and ending.
+     * Pattern is {@code "yyyy-MM-dd HH:mm:ss"} in UTC timezone.
+     */
+    public String begin, end;
+
+    /**
+     * Returns the constant value held by this object.
+     * Returns value should be interpreted as a {@link Period}.
+     */
+    @Override public Object getValue()                     {return this;}
+    @Override public Object evaluate(Object o)             {return this;}
+    @Override public <T> T  evaluate(Object o, Class<T> c) {return c.cast(this);}
+
+    /** Implements the visitor pattern (not used by Apache SIS). */
+    @Override public Object accept(ExpressionVisitor visitor, Object extraData) {
+        return visitor.visit(this, extraData);
+    }
+
+    /** Returns a bound of this period. */
+    @Override public org.opengis.temporal.Instant getBeginning() {return instant(begin);}
+    @Override public org.opengis.temporal.Instant getEnding()    {return instant(end);}
+
+    /** Wraps the value that defines a period. */
+    private static org.opengis.temporal.Instant instant(final String t) {
+        return new org.opengis.temporal.Instant() {
+            @Override public Date   getDate()  {return TestUtilities.date(t);}
+            @Override public String toString() {return "Instant[" + t + '[';}
+
+            /** Not needed for the tests. */
+            @Override public Identifier       getName()                              {throw new UnsupportedOperationException();}
+            @Override public TemporalPosition getTemporalPosition()                  {throw new UnsupportedOperationException();}
+            @Override public RelativePosition relativePosition(TemporalPrimitive o)  {throw new UnsupportedOperationException();}
+            @Override public Duration         distance(TemporalGeometricPrimitive o) {throw new UnsupportedOperationException();}
+            @Override public Duration         length()                               {throw new UnsupportedOperationException();}
+        };
+    }
+
+    /** Not needed for the tests. */
+    @Override public Identifier       getName()                              {throw new UnsupportedOperationException();}
+    @Override public RelativePosition relativePosition(TemporalPrimitive o)  {throw new UnsupportedOperationException();}
+    @Override public Duration         distance(TemporalGeometricPrimitive o) {throw new UnsupportedOperationException();}
+    @Override public Duration         length()                               {throw new UnsupportedOperationException();}
+
+    /**
+     * Hash code value. Used by the tests for checking the results of deserialization.
+     */
+    @Override
+    public int hashCode() {
+        return Objects.hash(begin, end);
+    }
+
+    /**
+     * Compare this period with given object. Used by the tests for checking the results of deserialization.
+     */
+    @Override
+    public boolean equals(final Object other) {
+        if (other instanceof PeriodLiteral) {
+            final PeriodLiteral p = (PeriodLiteral) other;
+            return Objects.equals(begin, p.begin) && Objects.equals(end, p.end);
+        }
+        return false;
+    }
+
+    /**
+     * Returns a string representation for debugging purposes.
+     */
+    @Override
+    public String toString() {
+        return "Period[" + begin + " ... " + end + ']';
+    }
+}
diff --git a/core/sis-feature/src/test/java/org/apache/sis/filter/TemporalFunctionTest.java b/core/sis-feature/src/test/java/org/apache/sis/filter/TemporalFunctionTest.java
index 78b3bdc..057d604 100644
--- a/core/sis-feature/src/test/java/org/apache/sis/filter/TemporalFunctionTest.java
+++ b/core/sis-feature/src/test/java/org/apache/sis/filter/TemporalFunctionTest.java
@@ -16,18 +16,19 @@
  */
 package org.apache.sis.filter;
 
-import static org.apache.sis.test.Assert.*;
+import org.opengis.filter.FilterFactory;
+import org.opengis.filter.temporal.BinaryTemporalOperator;
 import org.apache.sis.test.TestCase;
-import org.junit.Ignore;
 import org.junit.Test;
-import org.opengis.filter.Filter;
-import org.opengis.filter.FilterFactory2;
+
+import static org.apache.sis.test.Assert.*;
 
 
 /**
  * Tests {@link TemporalFunction} implementations.
  *
  * @author  Johann Sorel (Geomatys)
+ * @author  Martin Desruisseaux (Geomatys)
  * @version 1.0
  * @since   1.0
  * @module
@@ -36,122 +37,192 @@ public final strictfp class TemporalFunctionTest extends TestCase {
     /**
      * The factory to use for creating the objects to test.
      */
-    private final FilterFactory2 factory = new DefaultFilterFactory();
+    private final FilterFactory factory;
 
     /**
-     * Tests "After" (construction, evaluation, serialization, equality).
+     * The filter to test. This field shall be assigned by each {@code testFoo()} method by invoking
+     * a {@link #factory} method with {@link #expression1} and {@link #expression2} in arguments.
      */
-    @Ignore
-    @Test
-    public void testAfter() {
+    private BinaryTemporalOperator filter;
+
+    /**
+     * The expression to test. They are the arguments to be given to {@link #factory} method.
+     * Each expression will return a period made of {@link PeriodLiteral#begin} and {@link PeriodLiteral#end}.
+     * Date pattern is {@code "yyyy-MM-dd HH:mm:ss"} in UTC timezone.
+     */
+    private final PeriodLiteral expression1, expression2;
+
+    /**
+     * Creates a new test case.
+     */
+    public TemporalFunctionTest() {
+        factory = new DefaultFilterFactory();
+        expression1 = new PeriodLiteral();
+        expression2 = new PeriodLiteral();
+        expression1.begin = expression2.begin = "2010-04-20 10:00:00";
+        expression1.end   = expression2.end   = "2010-04-25 15:00:00";
+        expression1.begin = expression2.begin = "2010-04-20 10:00:00";
+        expression1.end   = expression2.end   = "2010-04-25 15:00:00";
     }
 
     /**
-     * Tests "AnyInteracts" (construction, evaluation, serialization, equality).
+     * Performs some validation on newly created filter.
+     *
+     * @param  name  expected filter name.
+     */
+    private void validate(final String name) {
+        assertInstanceOf("Expected SIS implementation.", TemporalFunction.class, filter);
+        final TemporalFunction f = ((TemporalFunction) filter);
+        assertEquals("name", name, f.getName());
+        assertSame("expression1", expression1, f.expression1);
+        assertSame("expression2", expression2, f.expression2);
+        assertSerializedEquals(filter);
+    }
+
+    /**
+     * Evaluates the filter.
+     */
+    private boolean evaluate() {
+        return filter.evaluate(null);
+    }
+
+    /**
+     * Tests "TEquals" (construction, evaluation, serialization, equality).
      */
-    @Ignore
     @Test
-    public void testAnyInteracts() {
+    public void testEquals() {
+        filter = factory.tequals(expression1, expression2);
+        validate("TEquals");
+        assertTrue(evaluate());
     }
 
     /**
      * Tests "Before" (construction, evaluation, serialization, equality).
      */
-    @Ignore
     @Test
     public void testBefore() {
+        filter = factory.before(expression1, expression2);
+        validate("Before");
+        assertFalse(evaluate());
     }
 
     /**
-     * Tests "Begins" (construction, evaluation, serialization, equality).
+     * Tests "After" (construction, evaluation, serialization, equality).
      */
-    @Ignore
     @Test
-    public void testBegins() {
+    public void testAfter() {
+        filter = factory.after(expression1, expression2);
+        validate("After");
+        assertFalse(evaluate());
     }
 
     /**
-     * Tests "BegunBy" (construction, evaluation, serialization, equality).
+     * Tests "Begins" (construction, evaluation, serialization, equality).
      */
-    @Ignore
     @Test
-    public void testBegunBy() {
+    public void testBegins() {
+        filter = factory.begins(expression1, expression2);
+        validate("Begins");
+        assertFalse(evaluate());
     }
 
     /**
-     * Tests "During" (construction, evaluation, serialization, equality).
+     * Tests "Ends" (construction, evaluation, serialization, equality).
      */
-    @Ignore
     @Test
-    public void testDuring() {
+    public void testEnds() {
+        filter = factory.ends(expression1, expression2);
+        validate("Ends");
+        assertFalse(evaluate());
     }
 
     /**
-     * Tests "EndedBy" (construction, evaluation, serialization, equality).
+     * Tests "BegunBy" (construction, evaluation, serialization, equality).
      */
-    @Ignore
     @Test
-    public void testEndedBy() {
+    public void testBegunBy() {
+        filter = factory.begunBy(expression1, expression2);
+        validate("BegunBy");
+        assertFalse(evaluate());
     }
 
     /**
-     * Tests "Ends" (construction, evaluation, serialization, equality).
+     * Tests "EndedBy" (construction, evaluation, serialization, equality).
      */
-    @Ignore
     @Test
-    public void testEnds() {
+    public void testEndedBy() {
+        filter = factory.endedBy(expression1, expression2);
+        validate("EndedBy");
+        assertFalse(evaluate());
     }
 
     /**
      * Tests "Meets" (construction, evaluation, serialization, equality).
      */
-    @Ignore
     @Test
     public void testMeets() {
+        filter = factory.meets(expression1, expression2);
+        validate("Meets");
+        assertFalse(evaluate());
     }
 
     /**
      * Tests "MetBy" (construction, evaluation, serialization, equality).
      */
-    @Ignore
     @Test
     public void testMetBy() {
+        filter = factory.metBy(expression1, expression2);
+        validate("MetBy");
+        assertFalse(evaluate());
     }
 
     /**
-     * Tests "OverlappedBy" (construction, evaluation, serialization, equality).
+     * Tests "During" (construction, evaluation, serialization, equality).
      */
-    @Ignore
     @Test
-    public void testOverlappedBy() {
+    public void testDuring() {
+        filter = factory.during(expression1, expression2);
+        validate("During");
+        assertFalse(evaluate());
     }
 
     /**
      * Tests "TContains" (construction, evaluation, serialization, equality).
      */
-    @Ignore
     @Test
-    public void testTContains() {
+    public void testContains() {
+        filter = factory.tcontains(expression1, expression2);
+        validate("TContains");
+        assertFalse(evaluate());
     }
 
     /**
-     * Tests "TEquals" (construction, evaluation, serialization, equality).
+     * Tests "TOverlaps" (construction, evaluation, serialization, equality).
      */
-    @Ignore
     @Test
-    public void testTEquals() {
+    public void testOverlaps() {
+        filter = factory.toverlaps(expression1, expression2);
+        validate("TOverlaps");
+        assertFalse(evaluate());
     }
 
     /**
-     * Tests "TOverlaps" (construction, evaluation, serialization, equality).
+     * Tests "OverlappedBy" (construction, evaluation, serialization, equality).
      */
-    @Ignore
     @Test
-    public void testTOverlaps() {
+    public void testOverlappedBy() {
+        filter = factory.overlappedBy(expression1, expression2);
+        validate("OverlappedBy");
+        assertFalse(evaluate());
     }
 
-    private static void assertFilter(boolean expected, Filter op) {
-        assertEquals(expected, op.evaluate(null));
-        assertSerializedEquals(op);
+    /**
+     * Tests "AnyInteracts" (construction, evaluation, serialization, equality).
+     */
+    @Test
+    public void testAnyInteracts() {
+        filter = factory.anyInteracts(expression1, expression2);
+        validate("AnyInteracts");
+        assertTrue(evaluate());
     }
 }


Mime
View raw message