This is an automated email from the ASF dual-hosted git repository.

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

commit 6e63051a6fef034289bf1a562837084075d4f802
Merge: c1009799e7 51124b9153
Author: Martin Desruisseaux <martin.desruisse...@geomatys.com>
AuthorDate: Sat Jun 1 00:11:11 2024 +0200

    Merge branch 'geoapi-3.1'

 .../org/apache/sis/filter/ComparisonFilter.java    |   4 +
 .../apache/sis/filter/DefaultFilterFactory.java    |  55 +-
 .../main/org/apache/sis/filter/TemporalFilter.java | 811 ++++-----------------
 .../org/apache/sis/filter/TemporalOperation.java   | 762 +++++++++++++++++++
 .../main/org/apache/sis/filter/TimeMethods.java    | 393 ++++++++++
 .../geoapi/filter/TemporalOperatorName.java        |   4 +
 .../org/apache/sis/filter/TemporalFilterTest.java  |  23 +-
 .../org.apache.sis.metadata/main/module-info.java  |   1 +
 .../sis/metadata/iso/acquisition/DefaultEvent.java |   9 +-
 .../iso/acquisition/DefaultRequestedDate.java      |  36 +-
 .../iso/acquisition/DefaultRequirement.java        |  23 +-
 .../sis/metadata/iso/citation/DefaultCitation.java |  23 +-
 .../metadata/iso/citation/DefaultCitationDate.java |  11 +-
 .../distribution/DefaultStandardOrderProcess.java  |  20 +-
 .../metadata/iso/extent/DefaultTemporalExtent.java |  40 +-
 .../apache/sis/metadata/iso/extent/Extents.java    |  95 ++-
 .../metadata/iso/identification/DefaultUsage.java  |  23 +-
 .../sis/metadata/privy/ImplementationHelper.java   |  23 -
 .../apache/sis/pending/temporal/DefaultPeriod.java |  12 +-
 .../sis/pending/temporal/TemporalUtilities.java    |  39 +-
 .../org/apache/sis/xml/bind/gco/GO_DateTime.java   |   3 +-
 .../org/apache/sis/xml/bind/gml/TM_Primitive.java  |  43 +-
 .../apache/sis/xml/bind/gml/TemporalAdapter.java   |   4 +-
 .../org/apache/sis/xml/bind/gml/TimeInstant.java   |  20 +-
 .../apache/sis/xml/bind/gml/TimePeriodBound.java   |   6 +-
 .../org/apache/sis/xml/privy/XmlUtilities.java     |  52 +-
 .../sis/metadata/iso/extent/DefaultExtentTest.java |  15 +-
 .../metadata/privy/ImplementationHelperTest.java   |  19 -
 .../org/apache/sis/metadata/xml/2007/Extent.xml    |   2 -
 .../org/apache/sis/metadata/xml/2016/Extent.xml    |   2 -
 .../apache/sis/xml/bind/gml/TimePeriodTest.java    |  19 +-
 .../org/apache/sis/xml/privy/XmlUtilitiesTest.java |  12 +-
 .../test/org/apache/sis/xml/test/TestCase.java     |  33 -
 .../sis/referencing/gazetteer/LocationFormat.java  |   7 +-
 .../main/org/apache/sis/io/wkt/Formatter.java      |  12 +-
 .../apache/sis/io/wkt/GeodeticObjectParser.java    |   3 +-
 .../sis/referencing/datum/AbstractDatum.java       |   3 +-
 .../referencing/datum/DefaultGeodeticDatum.java    |   4 +-
 .../org/apache/sis/referencing/internal/Epoch.java |   6 +-
 .../sis/referencing/privy/ExtentSelector.java      | 101 +--
 .../referencing/AbstractReferenceSystemTest.java   |   9 +-
 .../datum/DefaultGeodeticDatumTest.java            |   3 +-
 .../sis/referencing/privy/ExtentSelectorTest.java  |   5 +-
 .../apache/sis/test/integration/MetadataTest.java  |  29 +-
 .../sis/test/integration/MetadataVerticalTest.java |  10 +-
 .../storage/geotiff/reader/XMLMetadataTest.java    |   2 +-
 .../apache/sis/storage/base/MetadataBuilder.java   |   3 +-
 .../apache/sis/pending/geoapi/temporal/Period.java |   6 +-
 .../main/org/apache/sis/util/Classes.java          |  20 +-
 .../org/apache/sis/util/privy/TemporalDate.java    | 113 ++-
 .../main/org/apache/sis/util/resources/Errors.java |   5 +
 .../apache/sis/util/resources/Errors.properties    |   1 +
 .../apache/sis/util/resources/Errors_fr.properties |   1 +
 .../org/apache/sis/measure/RangeFormatTest.java    |   8 +-
 .../test/org/apache/sis/test/TestUtilities.java    |   4 +-
 .../sis/gui/metadata/IdentificationInfo.java       |   9 +-
 56 files changed, 1841 insertions(+), 1160 deletions(-)

diff --cc 
endorsed/src/org.apache.sis.feature/main/org/apache/sis/filter/DefaultFilterFactory.java
index 80379a395d,c020754996..03264883a2
--- 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/filter/DefaultFilterFactory.java
+++ 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/filter/DefaultFilterFactory.java
@@@ -32,12 -32,16 +32,13 @@@ import org.apache.sis.filter.sqlmm.Regi
  import org.apache.sis.util.ArgumentChecks;
  import org.apache.sis.util.iso.AbstractFactory;
  import org.apache.sis.util.resources.Errors;
+ import org.apache.sis.util.privy.Strings;
  
 -// Specific to the geoapi-3.1 and geoapi-4.0 branches:
 -import java.util.Iterator;
 -import java.time.Instant;
 -import org.opengis.filter.*;
 -import org.opengis.feature.Feature;
 -import org.opengis.filter.capability.AvailableFunction;
 -import org.opengis.filter.capability.FilterCapabilities;
 -import org.apache.sis.util.privy.AbstractMap;
 +// Specific to the main branch:
 +import org.apache.sis.feature.AbstractFeature;
 +import org.apache.sis.pending.geoapi.filter.MatchAction;
 +import org.apache.sis.pending.geoapi.filter.SpatialOperatorName;
 +import org.apache.sis.pending.geoapi.filter.DistanceOperatorName;
  
  
  /**
@@@ -128,14 -128,13 +132,13 @@@ public abstract class DefaultFilterFact
      }
  
      /**
 -     * Returns a factory operating on {@link Feature} instances.
 +     * Returns a factory operating on {@link AbstractFeature} instances.
       * The {@linkplain GeometryLibrary geometry library} will be the system 
default.
+      * The temporal objects can be {@link java.util.Date} or implementations 
of {@link java.time.temporal.Temporal}.
       *
 -     * @return factory operating on {@link Feature} instances.
 +     * @return factory operating on {@link AbstractFeature} instances.
-      *
-      * @todo The type of temporal objects is not yet determined.
       */
 -    public static FilterFactory<Feature, Object, Object> forFeatures() {
 +    public static DefaultFilterFactory<AbstractFeature, Object, Object> 
forFeatures() {
          return Features.DEFAULT;
      }
  
@@@ -643,11 -725,14 +646,11 @@@
       * @param  time1  expression fetching the first temporal value.
       * @param  time2  expression fetching the second temporal value.
       * @return a filter for the "After" operator between the two temporal 
values.
 -     *
 -     * @see TemporalOperatorName#AFTER
       */
 -    @Override
 -    public TemporalOperator<R> after(final Expression<R, ? extends T> time1,
 -                                     final Expression<R, ? extends T> time2)
 +    public Filter<R> after(final Expression<R, ? extends T> time1,
 +                           final Expression<R, ? extends T> time2)
      {
-         return new TemporalFilter.After<>(time1, time2);
+         return TemporalFilter.create(temporal, TemporalOperation.After::new, 
time1, time2);
      }
  
      /**
@@@ -656,11 -741,14 +659,11 @@@
       * @param  time1  expression fetching the first temporal value.
       * @param  time2  expression fetching the second temporal value.
       * @return a filter for the "Before" operator between the two temporal 
values.
 -     *
 -     * @see TemporalOperatorName#BEFORE
       */
 -    @Override
 -    public TemporalOperator<R> before(final Expression<R, ? extends T> time1,
 -                                      final Expression<R, ? extends T> time2)
 +    public Filter<R> before(final Expression<R, ? extends T> time1,
 +                            final Expression<R, ? extends T> time2)
      {
-         return new TemporalFilter.Before<>(time1, time2);
+         return TemporalFilter.create(temporal, TemporalOperation.Before::new, 
time1, time2);
      }
  
      /**
@@@ -669,11 -757,14 +672,11 @@@
       * @param  time1  expression fetching the first temporal value.
       * @param  time2  expression fetching the second temporal value.
       * @return a filter for the "Begins" operator between the two temporal 
values.
 -     *
 -     * @see TemporalOperatorName#BEGINS
       */
 -    @Override
 -    public TemporalOperator<R> begins(final Expression<R, ? extends T> time1,
 -                                      final Expression<R, ? extends T> time2)
 +    public Filter<R> begins(final Expression<R, ? extends T> time1,
 +                            final Expression<R, ? extends T> time2)
      {
-         return new TemporalFilter.Begins<>(time1, time2);
+         return TemporalFilter.create(temporal, TemporalOperation.Begins::new, 
time1, time2);
      }
  
      /**
@@@ -682,11 -773,14 +685,11 @@@
       * @param  time1  expression fetching the first temporal value.
       * @param  time2  expression fetching the second temporal value.
       * @return a filter for the "BegunBy" operator between the two temporal 
values.
 -     *
 -     * @see TemporalOperatorName#BEGUN_BY
       */
 -    @Override
 -    public TemporalOperator<R> begunBy(final Expression<R, ? extends T> time1,
 -                                       final Expression<R, ? extends T> time2)
 +    public Filter<R> begunBy(final Expression<R, ? extends T> time1,
 +                             final Expression<R, ? extends T> time2)
      {
-         return new TemporalFilter.BegunBy<>(time1, time2);
+         return TemporalFilter.create(temporal, 
TemporalOperation.BegunBy::new, time1, time2);
      }
  
      /**
@@@ -695,11 -789,14 +698,11 @@@
       * @param  time1  expression fetching the first temporal value.
       * @param  time2  expression fetching the second temporal value.
       * @return a filter for the "TContains" operator between the two temporal 
values.
 -     *
 -     * @see TemporalOperatorName#CONTAINS
       */
 -    @Override
 -    public TemporalOperator<R> tcontains(final Expression<R, ? extends T> 
time1,
 -                                         final Expression<R, ? extends T> 
time2)
 +    public Filter<R> tcontains(final Expression<R, ? extends T> time1,
 +                               final Expression<R, ? extends T> time2)
      {
-         return new TemporalFilter.Contains<>(time1, time2);
+         return TemporalFilter.create(temporal, 
TemporalOperation.Contains::new, time1, time2);
      }
  
      /**
@@@ -708,11 -805,14 +711,11 @@@
       * @param  time1  expression fetching the first temporal value.
       * @param  time2  expression fetching the second temporal value.
       * @return a filter for the "During" operator between the two temporal 
values.
 -     *
 -     * @see TemporalOperatorName#DURING
       */
 -    @Override
 -    public TemporalOperator<R> during(final Expression<R, ? extends T> time1,
 -                                      final Expression<R, ? extends T> time2)
 +    public Filter<R> during(final Expression<R, ? extends T> time1,
 +                            final Expression<R, ? extends T> time2)
      {
-         return new TemporalFilter.During<>(time1, time2);
+         return TemporalFilter.create(temporal, TemporalOperation.During::new, 
time1, time2);
      }
  
      /**
@@@ -721,11 -821,14 +724,11 @@@
       * @param  time1  expression fetching the first temporal value.
       * @param  time2  expression fetching the second temporal value.
       * @return a filter for the "TEquals" operator between the two temporal 
values.
 -     *
 -     * @see TemporalOperatorName#EQUALS
       */
 -    @Override
 -    public TemporalOperator<R> tequals(final Expression<R, ? extends T> time1,
 -                                       final Expression<R, ? extends T> time2)
 +    public Filter<R> tequals(final Expression<R, ? extends T> time1,
 +                             final Expression<R, ? extends T> time2)
      {
-         return new TemporalFilter.Equals<>(time1, time2);
+         return TemporalFilter.create(temporal, TemporalOperation.Equals::new, 
time1, time2);
      }
  
      /**
@@@ -734,11 -837,14 +737,11 @@@
       * @param  time1  expression fetching the first temporal value.
       * @param  time2  expression fetching the second temporal value.
       * @return a filter for the "TOverlaps" operator between the two temporal 
values.
 -     *
 -     * @see TemporalOperatorName#OVERLAPS
       */
 -    @Override
 -    public TemporalOperator<R> toverlaps(final Expression<R, ? extends T> 
time1,
 -                                         final Expression<R, ? extends T> 
time2)
 +    public Filter<R> toverlaps(final Expression<R, ? extends T> time1,
 +                               final Expression<R, ? extends T> time2)
      {
-         return new TemporalFilter.Overlaps<>(time1, time2);
+         return TemporalFilter.create(temporal, 
TemporalOperation.Overlaps::new, time1, time2);
      }
  
      /**
@@@ -747,11 -853,14 +750,11 @@@
       * @param  time1  expression fetching the first temporal value.
       * @param  time2  expression fetching the second temporal value.
       * @return a filter for the "Meets" operator between the two temporal 
values.
 -     *
 -     * @see TemporalOperatorName#MEETS
       */
 -    @Override
 -    public TemporalOperator<R> meets(final Expression<R, ? extends T> time1,
 -                                     final Expression<R, ? extends T> time2)
 +    public Filter<R> meets(final Expression<R, ? extends T> time1,
 +                           final Expression<R, ? extends T> time2)
      {
-         return new TemporalFilter.Meets<>(time1, time2);
+         return TemporalFilter.create(temporal, TemporalOperation.Meets::new, 
time1, time2);
      }
  
      /**
@@@ -760,11 -869,14 +763,11 @@@
       * @param  time1  expression fetching the first temporal value.
       * @param  time2  expression fetching the second temporal value.
       * @return a filter for the "Ends" operator between the two temporal 
values.
 -     *
 -     * @see TemporalOperatorName#ENDS
       */
 -    @Override
 -    public TemporalOperator<R> ends(final Expression<R, ? extends T> time1,
 -                                    final Expression<R, ? extends T> time2)
 +    public Filter<R> ends(final Expression<R, ? extends T> time1,
 +                          final Expression<R, ? extends T> time2)
      {
-         return new TemporalFilter.Ends<>(time1, time2);
+         return TemporalFilter.create(temporal, TemporalOperation.Ends::new, 
time1, time2);
      }
  
      /**
@@@ -773,11 -885,14 +776,11 @@@
       * @param  time1  expression fetching the first temporal value.
       * @param  time2  expression fetching the second temporal value.
       * @return a filter for the "OverlappedBy" operator between the two 
temporal values.
 -     *
 -     * @see TemporalOperatorName#OVERLAPPED_BY
       */
 -    @Override
 -    public TemporalOperator<R> overlappedBy(final Expression<R, ? extends T> 
time1,
 -                                            final Expression<R, ? extends T> 
time2)
 +    public Filter<R> overlappedBy(final Expression<R, ? extends T> time1,
 +                                  final Expression<R, ? extends T> time2)
      {
-         return new TemporalFilter.OverlappedBy<>(time1, time2);
+         return TemporalFilter.create(temporal, 
TemporalOperation.OverlappedBy::new, time1, time2);
      }
  
      /**
@@@ -786,11 -901,14 +789,11 @@@
       * @param  time1  expression fetching the first temporal value.
       * @param  time2  expression fetching the second temporal value.
       * @return a filter for the "MetBy" operator between the two temporal 
values.
 -     *
 -     * @see TemporalOperatorName#MET_BY
       */
 -    @Override
 -    public TemporalOperator<R> metBy(final Expression<R, ? extends T> time1,
 -                                     final Expression<R, ? extends T> time2)
 +    public Filter<R> metBy(final Expression<R, ? extends T> time1,
 +                           final Expression<R, ? extends T> time2)
      {
-         return new TemporalFilter.MetBy<>(time1, time2);
+         return TemporalFilter.create(temporal, TemporalOperation.MetBy::new, 
time1, time2);
      }
  
      /**
@@@ -799,11 -917,14 +802,11 @@@
       * @param  time1  expression fetching the first temporal value.
       * @param  time2  expression fetching the second temporal value.
       * @return a filter for the "EndedBy" operator between the two temporal 
values.
 -     *
 -     * @see TemporalOperatorName#ENDED_BY
       */
 -    @Override
 -    public TemporalOperator<R> endedBy(final Expression<R, ? extends T> time1,
 -                                       final Expression<R, ? extends T> time2)
 +    public Filter<R> endedBy(final Expression<R, ? extends T> time1,
 +                             final Expression<R, ? extends T> time2)
      {
-         return new TemporalFilter.EndedBy<>(time1, time2);
+         return TemporalFilter.create(temporal, 
TemporalOperation.EndedBy::new, time1, time2);
      }
  
      /**
@@@ -813,11 -934,14 +816,11 @@@
       * @param  time1  expression fetching the first temporal value.
       * @param  time2  expression fetching the second temporal value.
       * @return a filter for the "AnyInteracts" operator between the two 
temporal values.
 -     *
 -     * @see TemporalOperatorName#ANY_INTERACTS
       */
 -    @Override
 -    public TemporalOperator<R> anyInteracts(final Expression<R, ? extends T> 
time1,
 -                                            final Expression<R, ? extends T> 
time2)
 +    public Filter<R> anyInteracts(final Expression<R, ? extends T> time1,
 +                                  final Expression<R, ? extends T> time2)
      {
-         return new TemporalFilter.AnyInteracts<>(time1, time2);
+         return TemporalFilter.create(temporal, 
TemporalOperation.AnyInteracts::new, time1, time2);
      }
  
      /**
diff --cc 
endorsed/src/org.apache.sis.feature/main/org/apache/sis/filter/TemporalFilter.java
index ae78bad713,88ebd77415..21629a0fda
--- 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/filter/TemporalFilter.java
+++ 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/filter/TemporalFilter.java
@@@ -16,11 -16,15 +16,12 @@@
   */
  package org.apache.sis.filter;
  
- import java.time.Instant;
+ import org.apache.sis.util.Classes;
+ import org.apache.sis.feature.privy.FeatureExpression;
  
 -// Specific to the geoapi-3.1 and geoapi-4.0 branches:
 -import org.opengis.temporal.Period;
 -import org.opengis.filter.Filter;
 -import org.opengis.filter.Expression;
 -import org.opengis.filter.TemporalOperator;
 -import org.opengis.filter.TemporalOperatorName;
 +// Specific to the main branch:
 +import org.apache.sis.pending.geoapi.temporal.Period;
 +import org.apache.sis.pending.geoapi.filter.TemporalOperatorName;
  
  
  /**
@@@ -37,10 -35,11 +32,11 @@@
   * @author  Johann Sorel (Geomatys)
   * @author  Martin Desruisseaux (Geomatys)
   *
-  * @param  <T>  the type of resources (e.g. {@code Feature}) used as inputs.
 - * @param  <R>  the type of resources (e.g. {@link 
org.opengis.feature.Feature}) used as inputs.
++ * @param  <R>  the type of resources (e.g. {@code Feature}) used as inputs.
+  * @param  <T>  the base type of temporal objects, or {@code Object.class} 
for any type.
   */
- abstract class TemporalFilter<T> extends BinaryFunction<T,Object,Object>
-         implements Filter<T>, Optimization.OnFilter<T>
+ class TemporalFilter<R,T> extends BinaryFunction<R,T,T>
 -        implements TemporalOperator<R>, Optimization.OnFilter<R>
++        implements Filter<R>, Optimization.OnFilter<R>
  {
      /**
       * For cross-version compatibility.
diff --cc 
endorsed/src/org.apache.sis.feature/main/org/apache/sis/filter/TemporalOperation.java
index 0000000000,d826f84485..535990fc99
mode 000000,100644..100644
--- 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/filter/TemporalOperation.java
+++ 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/filter/TemporalOperation.java
@@@ -1,0 -1,762 +1,762 @@@
+ /*
+  * 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.io.Serializable;
+ import java.time.temporal.Temporal;
+ import org.apache.sis.util.Classes;
+ import org.apache.sis.util.privy.Strings;
+ import org.apache.sis.util.collection.WeakHashSet;
+ import static org.apache.sis.filter.TimeMethods.BEFORE;
+ import static org.apache.sis.filter.TimeMethods.AFTER;
+ import static org.apache.sis.filter.TimeMethods.EQUAL;
+ 
+ // Specific to the geoapi-3.1 and geoapi-4.0 branches:
 -import org.opengis.temporal.Period;
 -import org.opengis.filter.TemporalOperatorName;
++import org.apache.sis.pending.geoapi.temporal.Period;
++import org.apache.sis.pending.geoapi.filter.TemporalOperatorName;
+ 
+ 
+ /**
+  * Temporal operations between periods and/or instants.
+  * The nature of the operation depends on the subclass.
+  * Subclasses shall override at least one of the following methods:
+  *
+  * <ul>
+  *   <li>{@link #evaluate(T, T)}</li>
+  *   <li>{@link #evaluate(T, Period)}</li>
+  *   <li>{@link #evaluate(Period, T)}</li>
+  *   <li>{@link #evaluate(Period, Period)}</li>
+  * </ul>
+  *
+  * Instances of this classes are immutable and thread-safe.
+  * The same instances are shared by many filters.
+  *
+  * @author  Johann Sorel (Geomatys)
+  * @author  Martin Desruisseaux (Geomatys)
+  *
+  * @param  <T>  the base type of temporal objects, or {@code Object.class} 
for any type.
+  */
+ abstract class TemporalOperation<T> implements Serializable {
+     /**
+      * For cross-version compatibility.
+      */
+     private static final long serialVersionUID = -5304814915639460679L;
+ 
+     /**
+      * Temporal operations created in the current JVM.
+      */
+     @SuppressWarnings("unchecked")
+     private static final WeakHashSet<TemporalOperation<?>> POOL = new 
WeakHashSet<>((Class) TemporalOperation.class);
+ 
+     /**
+      * The set of methods to invoke for performing "is before", "is after" or 
"is equal" comparisons.
+      */
+     protected final TimeMethods<T> comparators;
+ 
+     /**
+      * Creates a new temporal operation.
+      *
+      * @param  comparators  the set of methods to invoke for performing 
comparisons.
+      */
+     protected TemporalOperation(final TimeMethods<T> comparators) {
+         this.comparators = comparators;
+     }
+ 
+     /**
+      * Returns a unique, shared instance of this operation.
+      *
+      * @return a unique instance equal to {@code this}.
+      */
+     public final TemporalOperation<T> unique() {
+         return POOL.unique(this);
+     }
+ 
+     /**
+      * Returns a hash code value for this operation.
+      * Used for {@link #unique()} implementation.
+      */
+     @Override
+     public final int hashCode() {
+         return getClass().hashCode() + 31 * comparators.type.hashCode();
+     }
+ 
+     /**
+      * Compares the given object with this operation for equality.
+      * Used for {@link #unique()} implementation.
+      */
+     @Override
+     public final boolean equals(final Object other) {
+         return (other != null) && (other.getClass() == getClass()) &&
+                 ((TemporalOperation) other).comparators.type == 
comparators.type;
+     }
+ 
+     /**
+      * Returns a string representation for debugging purposes.
+      */
+     @Override
+     public final String toString() {
+         return Strings.toString(getClass(),
+                 "operator", getOperatorType().identifier(),
+                 "type", comparators.type.getSimpleName());
+     }
+ 
+     /**
+      * Returns an identification of this operation.
+      */
+     public abstract TemporalOperatorName getOperatorType();
+ 
+     /**
+      * Returns the mathematical symbol for this temporal operation.
+      *
+      * @return the mathematical symbol, or 0 if none.
+      */
+     protected char symbol() {
+         return (char) 0;
+     }
+ 
+     /**
+      * Evaluates the filter between two temporal objects.
+      * Both arguments given to this method shall be non-null.
+      */
+     protected boolean evaluate(T self, T other) {
+         return false;
+     }
+ 
+     /**
+      * Evaluates the filter between a temporal object and a period.
+      * Both arguments given to this method shall be non-null, but period 
begin or end instant may be null.
+      *
+      * <p><b>Note:</b> this relationship is not defined by ISO 19108. This 
method should be overridden
+      * only when an ISO 19108 extension can be easily defined, for example 
for the "equal" operation.</p>
+      */
+     protected boolean evaluate(T self, Period other) {
+         return false;
+     }
+ 
+     /**
+      * Evaluates the filter between a period and a temporal object.
+      * Both arguments given to this method shall be non-null, but period 
begin or end instant may be null.
+      * Note: the {@code self} and {@code other} argument names are chosen to 
match ISO 19108 tables.
+      */
+     protected boolean evaluate(Period self, T other) {
+         return false;
+     }
+ 
+     /**
+      * Evaluates the filter between two periods.
+      * Both arguments given to this method shall be non-null, but period 
begin or end instant may be null.
+      * Note: the {@code self} and {@code other} argument names are chosen to 
match ISO 19108 tables.
+      */
+     protected abstract boolean evaluate(Period self, Period other);
+ 
+     /**
+      * Returns {@code true} if {@code other} is non-null and the specified 
comparison evaluates to {@code true}.
+      * This is a helper function for {@code evaluate(…)} methods 
implementations.
+      *
+      * @param  test   enumeration value such as {@link TimeMethods#BEFORE} or 
{@link TimeMethods#AFTER}.
+      * @param  self   the object on which to invoke the method identified by 
{@code test}.
+      * @param  other  the argument to give to the test method call, or {@code 
null} if none.
+      * @return the result of performing the comparison identified by {@code 
test}.
 -     * @throws InvalidFilterValueException if the two objects cannot be 
compared.
++     * @throws IllegalArgumentException if the two objects cannot be compared.
+      */
+     final boolean compare(final int test, final T self, final Temporal other) 
{
+         return (other != null) && comparators.compare(test, self, other);
+     }
+ 
+     /**
+      * Returns {@code true} if both arguments are non-null and the specified 
comparison evaluates to {@code true}.
+      * This is a helper function for {@code evaluate(…)} methods 
implementations.
+      *
+      * @param  test   enumeration value such as {@link TimeMethods#BEFORE} or 
{@link TimeMethods#AFTER}.
+      * @param  self   the object on which to invoke the method identified by 
{@code test}, or {@code null} if none.
+      * @param  other  the argument to give to the test method call, or {@code 
null} if none.
+      * @return the result of performing the comparison identified by {@code 
test}.
 -     * @throws InvalidFilterValueException if the two objects cannot be 
compared.
++     * @throws IllegalArgumentException if the two objects cannot be compared.
+      */
+     @SuppressWarnings("unchecked")
+     static boolean compare(final int test, final Temporal self, final 
Temporal other) {
+         return (self != null) && (other != null) && TimeMethods.compare(test,
+                 (Class) Classes.findCommonClass(self.getClass(), 
other.getClass()), self, other);
+     }
+ 
+ 
+     /**
+      * Reference to a sub-class constructor.
+      *
+      * @param <T> type of temporal object.
+      */
+     @FunctionalInterface
+     static interface Factory {
+         /**
+          * Creates a new temporal operation.
+          *
+          * @param  <T>          type of temporal objects that the operation 
will accept.
+          * @param  comparators  the set of methods to invoke for performing 
comparisons.
+          * @return the temporal operation using the given "is before", "is 
after" and "is equal" methods.
+          */
+         <T> TemporalOperation<T> create(TimeMethods<T> comparators);
+     }
+ 
+ 
+     /**
+      * The {@code "TEquals"} (=) operation. Defined by ISO 19108 as:
+      * <ul>
+      *   <li>{@literal self = other}</li>
+      *   <li>{@literal self.begin = other.begin  AND  self.end = 
other.end}</li>
+      * </ul>
+      *
+      * @param  <T>  the base type of temporal objects.
+      */
+     static final class Equals<T> extends TemporalOperation<T> {
+         /** For cross-version compatibility during (de)serialization. */
+         private static final long serialVersionUID = -6060822291802339424L;
+ 
+         /** Creates a new operation. */
+         Equals(TimeMethods<T> comparators) {
+             super(comparators);
+         }
+ 
+         /** Identification of this operation. */
+         @Override public TemporalOperatorName getOperatorType() {
+             return TemporalOperatorName.EQUALS;
+         }
+ 
+         /** Symbol of this operation. */
+         @Override protected char symbol() {
+             return '=';
+         }
+ 
+         /** Condition defined by ISO 19108:2002 §5.2.3.5. */
+         @Override protected boolean evaluate(T self, T other) {
+             return comparators.isEqual.test(self, other);
+         }
+ 
+         /** Extension to ISO 19108: handle instant as a tiny period. */
+         @Override public boolean evaluate(T self, Period other) {
+             return compare(EQUAL, self, other.getBeginning()) &&
+                    compare(EQUAL, self, other.getEnding());
+         }
+ 
+         /** Extension to ISO 19108: handle instant as a tiny period. */
+         @Override public boolean evaluate(Period self, T other) {
+             return compare(EQUAL, other, self.getBeginning()) &&
+                    compare(EQUAL, other, self.getEnding());
+         }
+ 
+         /** Condition defined by ISO 19108:2006 (corrigendum) §5.2.3.5. */
+         @Override public boolean evaluate(Period self, Period other) {
+             return compare(EQUAL, self.getBeginning(), other.getBeginning()) 
&&
+                    compare(EQUAL, self.getEnding(),    other.getEnding());
+         }
+     }
+ 
+ 
+     /**
+      * The {@code "Before"} {@literal (<)} operation. 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>
+      *
+      * @param  <T>  the base type of temporal objects.
+      */
+     static final class Before<T> extends TemporalOperation<T> {
+         /** For cross-version compatibility during (de)serialization. */
+         private static final long serialVersionUID = -3422629447456003982L;
+ 
+         /** Creates a new operation. */
+         Before(TimeMethods<T> comparators) {
+             super(comparators);
+         }
+ 
+         /** Identification of this operation. */
+         @Override public TemporalOperatorName getOperatorType() {
+             return TemporalOperatorName.BEFORE;
+         }
+ 
+         /** Symbol of this operation. */
+         @Override protected char symbol() {
+             return '<';
+         }
+ 
+         /** Condition defined by ISO 19108:2002 §5.2.3.5. */
+         @Override protected boolean evaluate(T self, T other) {
+             return comparators.isBefore.test(self, other);
+         }
+ 
+         /** Relationship not defined by ISO 19108:2006. */
+         @Override public boolean evaluate(T self, Period other) {
+             return compare(BEFORE, self, other.getBeginning());
+         }
+ 
+         /** Condition defined by ISO 19108:2006 (corrigendum) §5.2.3.5. */
+         @Override public boolean evaluate(Period self, T other) {
+             return compare(AFTER, other, self.getEnding());
+         }
+ 
+         /** Condition defined by ISO 19108:2006 (corrigendum) §5.2.3.5. */
+         @Override public boolean evaluate(Period self, Period other) {
+             return compare(BEFORE, self.getEnding(), other.getBeginning());
+         }
+     }
+ 
+ 
+     /**
+      * The {@code "After"} {@literal (>)} operation. 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>
+      *
+      * @param  <T>  the base type of temporal objects.
+      */
+     static final class After<T> extends TemporalOperation<T> {
+         /** For cross-version compatibility during (de)serialization. */
+         private static final long serialVersionUID = 5410476260417497682L;
+ 
+         /** Creates a new operation. */
+         After(TimeMethods<T> comparators) {
+             super(comparators);
+         }
+ 
+         /** Identification of this operation. */
+         @Override public TemporalOperatorName getOperatorType() {
+             return TemporalOperatorName.AFTER;
+         }
+ 
+         /** Symbol of this operation. */
+         @Override protected char symbol() {
+             return '>';
+         }
+ 
+         /** Condition defined by ISO 19108:2002 §5.2.3.5. */
+         @Override protected boolean evaluate(T self, T other) {
+             return comparators.isAfter.test(self, other);
+         }
+ 
+         /** Relationship not defined by ISO 19108:2006. */
+         @Override public boolean evaluate(T self, Period other) {
+             return compare(AFTER, self, other.getEnding());
+         }
+ 
+         /** Condition defined by ISO 19108:2006 (corrigendum) §5.2.3.5. */
+         @Override public boolean evaluate(Period self, T other) {
+             return compare(BEFORE, other, self.getBeginning());
+         }
+ 
+         /** Condition defined by ISO 19108:2006 (corrigendum) §5.2.3.5. */
+         @Override public boolean evaluate(Period self, Period other) {
+             return compare(AFTER, self.getBeginning(), other.getEnding());
+         }
+     }
+ 
+ 
+     /**
+      * The {@code "Begins"} operation. Defined by ISO 19108 as:
+      * <ul>
+      *   <li>{@literal self.begin = other.begin  AND  self.end < 
other.end}</li>
+      * </ul>
+      *
+      * @param  <T>  the base type of temporal objects.
+      */
+     static final class Begins<T> extends TemporalOperation<T> {
+         /** For cross-version compatibility during (de)serialization. */
+         private static final long serialVersionUID = -7880699329127762233L;
+ 
+         /** Creates a new operation. */
+         Begins(TimeMethods<T> comparators) {
+             super(comparators);
+         }
+ 
+         /** Identification of this operation. */
+         @Override public TemporalOperatorName getOperatorType() {
+             return TemporalOperatorName.BEGINS;
+         }
+ 
+         /** Condition defined by ISO 19108:2006 (corrigendum) §5.2.3.5. */
+         @Override public boolean evaluate(final Period self, final Period 
other) {
+             return compare(EQUAL,  self.getBeginning(), other.getBeginning()) 
&&
+                    compare(BEFORE, self.getEnding(),    other.getEnding());
+         }
+     }
+ 
+ 
+     /**
+      * The {@code "Ends"} operation. Defined by ISO 19108 as:
+      * <ul>
+      *   <li>{@literal self.begin > other.begin  AND  self.end = 
other.end}</li>
+      * </ul>
+      *
+      * @param  <T>  the base type of temporal objects.
+      */
+     static final class Ends<T> extends TemporalOperation<T> {
+         /** For cross-version compatibility during (de)serialization. */
+         private static final long serialVersionUID = -5508229966320563437L;
+ 
+         /** Creates a new operation. */
+         Ends(TimeMethods<T> comparators) {
+             super(comparators);
+         }
+ 
+         /** Identification of this operation. */
+         @Override public TemporalOperatorName getOperatorType() {
+             return TemporalOperatorName.ENDS;
+         }
+ 
+         /** Condition defined by ISO 19108:2006 (corrigendum) §5.2.3.5. */
+         @Override public boolean evaluate(final Period self, final Period 
other) {
+             return compare(EQUAL, self.getEnding(),    other.getEnding()) &&
+                    compare(AFTER, self.getBeginning(), other.getBeginning());
+         }
+     }
+ 
+ 
+     /**
+      * The {@code "BegunBy"} operation. 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>
+      *
+      * @param  <T>  the base type of temporal objects.
+      */
+     static final class BegunBy<T> extends TemporalOperation<T> {
+         /** For cross-version compatibility during (de)serialization. */
+         private static final long serialVersionUID = -7212413827394364384L;
+ 
+         /** Creates a new operation. */
+         BegunBy(TimeMethods<T> comparators) {
+             super(comparators);
+         }
+ 
+         /** Identification of this operation. */
+         @Override public TemporalOperatorName getOperatorType() {
+             return TemporalOperatorName.BEGUN_BY;
+         }
+ 
+         /** Condition defined by ISO 19108:2006 (corrigendum) §5.2.3.5. */
+         @Override public boolean evaluate(Period self, T other) {
+             return compare(EQUAL, other, self.getBeginning());
+         }
+ 
+         /** Condition defined by ISO 19108:2006 (corrigendum) §5.2.3.5. */
+         @Override public boolean evaluate(final Period self, final Period 
other) {
+             return compare(EQUAL, self.getBeginning(), other.getBeginning()) 
&&
+                    compare(AFTER, self.getEnding(),    other.getEnding());
+         }
+     }
+ 
+ 
+     /**
+      * The {@code "EndedBy"} operation. 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>
+      *
+      * @param  <T>  the base type of temporal objects.
+      */
+     static final class EndedBy<T> extends TemporalOperation<T> {
+         /** For cross-version compatibility during (de)serialization. */
+         private static final long serialVersionUID = 8586566103462153666L;
+ 
+         /** Creates a new operation. */
+         EndedBy(TimeMethods<T> comparators) {
+             super(comparators);
+         }
+ 
+         /** Identification of this operation. */
+         @Override public TemporalOperatorName getOperatorType() {
+             return TemporalOperatorName.ENDED_BY;
+         }
+ 
+         /** Condition defined by ISO 19108:2006 (corrigendum) §5.2.3.5. */
+         @Override public boolean evaluate(final Period self, final T other) {
+             return compare(EQUAL, other, self.getEnding());
+         }
+ 
+         /** Condition defined by ISO 19108:2006 (corrigendum) §5.2.3.5. */
+         @Override public boolean evaluate(final Period self, final Period 
other) {
+             return compare(EQUAL,  self.getEnding(),    other.getEnding()) &&
+                    compare(BEFORE, self.getBeginning(), other.getBeginning());
+         }
+     }
+ 
+ 
+     /**
+      * The {@code "Meets"} operation. Defined by ISO 19108 as:
+      * <ul>
+      *   <li>{@literal self.end = other.begin}</li>
+      * </ul>
+      *
+      * @param  <T>  the base type of temporal objects.
+      */
+     static final class Meets<T> extends TemporalOperation<T> {
+         /** For cross-version compatibility during (de)serialization. */
+         private static final long serialVersionUID = -3534843269384858443L;
+ 
+         /** Creates a new operation. */
+         Meets(TimeMethods<T> comparators) {
+             super(comparators);
+         }
+ 
+         /** Identification of this operation. */
+         @Override public TemporalOperatorName getOperatorType() {
+             return TemporalOperatorName.MEETS;
+         }
+ 
+         /** Extension to ISO 19108: handle instant as a tiny period. */
+         @Override public boolean evaluate(final T self, final T other) {
+             return comparators.isEqual.test(self, other);
+         }
+ 
+         /** Extension to ISO 19108: handle instant as a tiny period. */
+         @Override public boolean evaluate(final T self, final Period other) {
+             return compare(EQUAL, self, other.getBeginning());
+         }
+ 
+         /** Extension to ISO 19108: handle instant as a tiny period. */
+         @Override public boolean evaluate(final Period self, final T other) {
+             return compare(EQUAL, other, self.getEnding());
+         }
+ 
+         /** Condition defined by ISO 19108:2006 (corrigendum) §5.2.3.5. */
+         @Override public boolean evaluate(final Period self, final Period 
other) {
+             return compare(EQUAL, self.getEnding(), other.getBeginning());
+         }
+     }
+ 
+ 
+     /**
+      * The {@code "MetBy"} operation. Defined by ISO 19108 as:
+      * <ul>
+      *   <li>{@literal self.begin = other.end}</li>
+      * </ul>
+      *
+      * @param  <T>  the base type of temporal objects.
+      */
+     static final class MetBy<T> extends TemporalOperation<T> {
+         /** For cross-version compatibility during (de)serialization. */
+         private static final long serialVersionUID = 5358059498707330482L;
+ 
+         /** Creates a new operation. */
+         MetBy(TimeMethods<T> comparators) {
+             super(comparators);
+         }
+ 
+         /** Identification of this operation. */
+         @Override public TemporalOperatorName getOperatorType() {
+             return TemporalOperatorName.MET_BY;
+         }
+ 
+         /** Extension to ISO 19108: handle instant as a tiny period. */
+         @Override public boolean evaluate(final T self, final T other) {
+             return comparators.isEqual.test(self, other);
+         }
+ 
+         /** Extension to ISO 19108: handle instant as a tiny period. */
+         @Override public boolean evaluate(final T self, final Period other) {
+             return compare(EQUAL, self, other.getEnding());
+         }
+ 
+         /** Extension to ISO 19108: handle instant as a tiny period. */
+         @Override public boolean evaluate(final Period self, final T other) {
+             return compare(EQUAL, other, self.getBeginning());
+         }
+ 
+         /** Condition defined by ISO 19108:2006 (corrigendum) §5.2.3.5. */
+         @Override public boolean evaluate(final Period self, final Period 
other) {
+             return compare(EQUAL, self.getBeginning(), other.getEnding());
+         }
+     }
+ 
+ 
+     /**
+      * The {@code "During"} operation. Defined by ISO 19108 as:
+      * <ul>
+      *   <li>{@literal self.begin > other.begin  AND  self.end < 
other.end}</li>
+      * </ul>
+      *
+      * @param  <T>  the base type of temporal objects.
+      */
+     static final class During<T> extends TemporalOperation<T> {
+         /** For cross-version compatibility during (de)serialization. */
+         private static final long serialVersionUID = -4674319635076886196L;
+ 
+         /** Creates a new operation. */
+         During(TimeMethods<T> comparators) {
+             super(comparators);
+         }
+ 
+         /** Identification of this operation. */
+         @Override public TemporalOperatorName getOperatorType() {
+             return TemporalOperatorName.DURING;
+         }
+ 
+         /** Symbol of this operation. */
+         @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 compare(AFTER,  self.getBeginning(), other.getBeginning()) 
&&
+                    compare(BEFORE, self.getEnding(),    other.getEnding());
+         }
+     }
+ 
+ 
+     /**
+      * The {@code "TContains"} operation. 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>
+      *
+      * @param  <T>  the base type of temporal objects.
+      */
+     static final class Contains<T> extends TemporalOperation<T> {
+         /** For cross-version compatibility during (de)serialization. */
+         private static final long serialVersionUID = 9107531246948034411L;
+ 
+         /** Creates a new operation. */
+         Contains(TimeMethods<T> comparators) {
+             super(comparators);
+         }
+ 
+         /** Identification of this operation. */
+         @Override public TemporalOperatorName getOperatorType() {
+             return TemporalOperatorName.CONTAINS;
+         }
+ 
+         /** Symbol of this operation. */
+         @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 T other) {
+             return compare(AFTER,  other, self.getBeginning()) &&
+                    compare(BEFORE, other, self.getEnding());
+         }
+ 
+         /** Condition defined by ISO 19108:2006 (corrigendum) §5.2.3.5. */
+         @Override public boolean evaluate(final Period self, final Period 
other) {
+             return compare(BEFORE, self.getBeginning(), other.getBeginning()) 
&&
+                    compare(AFTER,  self.getEnding(),    other.getEnding());
+         }
+     }
+ 
+ 
+     /**
+      * The {@code "TOverlaps"} operation. Defined by ISO 19108 as:
+      * <ul>
+      *   <li>{@literal self.begin < other.begin  AND  self.end > other.begin  
AND  self.end < other.end}</li>
+      * </ul>
+      *
+      * @param  <T>  the base type of temporal objects.
+      */
+     static final class Overlaps<T> extends TemporalOperation<T> {
+         /** For cross-version compatibility during (de)serialization. */
+         private static final long serialVersionUID = 1517443045593389773L;
+ 
+         /** Creates a new operation. */
+         Overlaps(TimeMethods<T> comparators) {
+             super(comparators);
+         }
+ 
+         /** Identification of this operation. */
+         @Override public TemporalOperatorName getOperatorType() {
+             return TemporalOperatorName.OVERLAPS;
+         }
+ 
+         /** Condition defined by ISO 19108:2006 (corrigendum) §5.2.3.5. */
+         @Override public boolean evaluate(final Period self, final Period 
other) {
+             final Temporal selfBegin, selfEnd, otherBegin, otherEnd;
+             return ((otherBegin = other.getBeginning()) != null) &&
+                    ((selfBegin  = self .getBeginning()) != null) && 
compare(BEFORE, selfBegin, otherBegin) &&
+                    ((selfEnd    = self .getEnding())    != null) && 
compare(AFTER,  selfEnd,   otherBegin) &&
+                    ((otherEnd   = other.getEnding())    != null) && 
compare(BEFORE, selfEnd,   otherEnd);
+         }
+     }
+ 
+ 
+     /**
+      * The {@code "OverlappedBy"} operation. Defined by ISO 19108 as:
+      * <ul>
+      *   <li>{@literal self.begin > other.begin  AND  self.begin < other.end  
AND  self.end > other.end}</li>
+      * </ul>
+      *
+      * @param  <T>  the base type of temporal objects.
+      */
+     static final class OverlappedBy<T> extends TemporalOperation<T> {
+         /** For cross-version compatibility during (de)serialization. */
+         private static final long serialVersionUID = 2228673820507226463L;
+ 
+         /** Creates a new operation. */
+         OverlappedBy(TimeMethods<T> comparators) {
+             super(comparators);
+         }
+ 
+         /** Identification of this operation. */
+         @Override public TemporalOperatorName getOperatorType() {
+             return TemporalOperatorName.OVERLAPPED_BY;
+         }
+ 
+         /** Condition defined by ISO 19108:2006 (corrigendum) §5.2.3.5. */
+         @Override public boolean evaluate(final Period self, final Period 
other) {
+             final Temporal selfBegin, selfEnd, otherBegin, otherEnd;
+             return ((selfBegin  = self .getBeginning()) != null) &&
+                    ((otherBegin = other.getBeginning()) != null) && 
compare(AFTER,  selfBegin,  otherBegin) &&
+                    ((otherEnd   = other.getEnding())    != null) && 
compare(BEFORE, selfBegin,  otherEnd)   &&
+                    ((selfEnd    = self .getEnding())    != null) && 
compare(AFTER,  selfEnd,    otherEnd);
+         }
+     }
+ 
+ 
+     /**
+      * The {@code "AnyInteracts"} filter.
+      * This is a shortcut for NOT (Before OR Meets OR MetBy OR After).
+      *
+      * @param  <T>  the base type of temporal objects.
+      */
+     static final class AnyInteracts<T> extends TemporalOperation<T> {
+         /** For cross-version compatibility during (de)serialization. */
+         private static final long serialVersionUID = 5972351564286442392L;
+ 
+         /** Creates a new operation. */
+         AnyInteracts(TimeMethods<T> comparators) {
+             super(comparators);
+         }
+ 
+         /** Identification of this operation. */
+         @Override public TemporalOperatorName getOperatorType() {
+             return TemporalOperatorName.ANY_INTERACTS;
+         }
+ 
+         /** Condition defined by OGC filter specification. */
+         @Override public boolean evaluate(final Period self, final Period 
other) {
+             final Temporal selfBegin, selfEnd, otherBegin, otherEnd;
+             return ((selfBegin  = self .getBeginning()) != null) &&
+                    ((otherEnd   = other.getEnding())    != null) && 
compare(BEFORE, selfBegin, otherEnd) &&
+                    ((selfEnd    = self .getEnding())    != null) &&
+                    ((otherBegin = other.getBeginning()) != null) && 
compare(AFTER, selfEnd, otherBegin);
+         }
+     }
+ }
diff --cc 
endorsed/src/org.apache.sis.feature/main/org/apache/sis/filter/TimeMethods.java
index 0000000000,11cc0ca6b7..18d60debd9
mode 000000,100644..100644
--- 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/filter/TimeMethods.java
+++ 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/filter/TimeMethods.java
@@@ -1,0 -1,396 +1,393 @@@
+ /*
+  * 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.Map;
+ import java.util.Date;
+ import java.time.Instant;
+ import java.time.Year;
+ import java.time.YearMonth;
+ import java.time.MonthDay;
+ import java.time.LocalTime;
+ import java.time.OffsetTime;
+ import java.time.OffsetDateTime;
+ import java.time.DateTimeException;
+ import java.time.chrono.ChronoLocalDate;
+ import java.time.chrono.ChronoLocalDateTime;
+ import java.time.chrono.ChronoZonedDateTime;
+ import java.time.temporal.ChronoField;
+ import java.time.temporal.Temporal;
+ import java.time.temporal.TemporalAccessor;
+ import java.util.function.BiPredicate;
+ import java.lang.reflect.Modifier;
+ import java.io.Serializable;
+ import java.io.ObjectStreamException;
+ import org.apache.sis.util.privy.Strings;
+ import org.apache.sis.util.resources.Errors;
+ 
 -// Specific to the geoapi-3.1 and geoapi-4.0 branches:
 -import org.opengis.filter.InvalidFilterValueException;
 -
+ 
+ /**
+  * Provides the <i>is before</i> and <i>is after</i> operations for various 
{@code java.time} objects.
+  * This class delegates to the {@code isBefore(T)} or {@code isAfter(T)} 
methods of each supported classes.
+  *
+  * Instances of this classes are immutable and thread-safe.
+  * The same instance can be shared by many {@link TemporalOperation} 
instances.
+  *
+  * <h2>Design note about alternative approaches</h2>
+  * We do not delegate to {@link Comparable#compareTo(Object)} because the 
latter method compares not only
+  * positions on the timeline, but also other properties not relevant to an 
"is before" or "is after" test.
+  * We could use {@link ChronoLocalDate#timeLineOrder()} comparators instead, 
but those comparators are not
+  * defined for every classes where the "is before" and "is after" methods 
differ from "compare to" method.
+  * Furthermore, some temporal classes override {@code isBefore(T)} or {@code 
isAfter(T)} for performance.
+  *
+  * @param  <T>  the base type of temporal objects, or {@code Object.class} 
for any type.
+  *
+  * @author  Martin Desruisseaux (Geomatys)
+  */
+ class TimeMethods<T> implements Serializable {
+     /**
+      * For cross-version compatibility.
+      */
+     private static final long serialVersionUID = 1075289362575825939L;
+ 
+     /**
+      * The type of temporal objects accepted by this set of operations.
+      */
+     public final Class<T> type;
+ 
+     /**
+      * Enumeration values for a test to apply.
+      *
+      * @see #compare(int, T, TemporalAccessor)
+      */
+     static final int BEFORE=1, AFTER=2, EQUAL=0;
+ 
+     /**
+      * Predicate to execute for testing the ordering between temporal objects.
+      * This comparison operator differs from the {@code compareTo(…)} method 
in that it compares only the
+      * positions on the timeline, ignoring metadata such as the calendar used 
for representing positions.
+      */
+     public final transient BiPredicate<T,T> isBefore, isAfter, isEqual;
+ 
+     /**
+      * Creates a new set of operators. This method is for subclasses only.
+      * For getting a {@code TimeMethods} instance, see {@link #find(Class)}.
+      */
+     private TimeMethods(final Class<T> type,
+             final BiPredicate<T,T> isBefore,
+             final BiPredicate<T,T> isAfter,
+             final BiPredicate<T,T> isEqual)
+     {
+         this.type     = type;
+         this.isBefore = isBefore;
+         this.isAfter  = isAfter;
+         this.isEqual  = isEqual;
+     }
+ 
+     /**
+      * Returns whether the end point will be determined dynamically every 
time that a method is invoked.
+      *
+      * @return whether the methods are determined dynamically on an 
instance-by-instance basis.
+      */
+     public boolean isDynamic() {
+         return false;
+     }
+ 
+     /**
+      * Delegates the comparison to the method identified by the {@code test} 
argument.
+      * This method is overridden in subclasses where the delegation can be 
more direct.
+      *
+      * @param  test   {@link #BEFORE}, {@link #AFTER} or {@link #EQUAL}.
+      * @param  self   the object on which to invoke the method identified by 
{@code test}.
+      * @param  other  the argument to give to the test method call.
+      * @return the result of performing the comparison identified by {@code 
test}.
+      */
+     boolean delegate(final int test, final T self, final T other) {
+         final BiPredicate<T,T> p;
+         switch (test) {
+             case BEFORE: p = isBefore; break;
+             case AFTER:  p = isAfter;  break;
+             case EQUAL:  p = isEqual;  break;
+             default: throw new AssertionError(test);
+         }
+         return p.test(self, other);
+     }
+ 
+     /**
+      * Compares an object of class {@code <T>} with a temporal object of 
unknown class.
+      * The other object is typically the beginning or ending of a period.
+      *
+      * @param  test   {@link #BEFORE}, {@link #AFTER} or {@link #EQUAL}.
+      * @param  self   the object on which to invoke the method identified by 
{@code test}.
+      * @param  other  the argument to give to the test method call.
+      * @return the result of performing the comparison identified by {@code 
test}.
 -     * @throws InvalidFilterValueException if the two objects cannot be 
compared.
++     * @throws IllegalArgumentException if the two objects cannot be compared.
+      */
+     @SuppressWarnings("unchecked")
+     final boolean compare(final int test, final T self, final 
TemporalAccessor other) {
+         if (type.isInstance(other)) {
+             return delegate(test, self, (T) other);         // Safe because 
of above `isInstance(…)` check.
+         }
+         return compareAsInstants(test, accessor(self), other);
+     }
+ 
+     /**
+      * Compares two temporal objects of unknown class. This method needs to 
check for specialized implementations
+      * before to delegate to {@link Comparable#compareTo(Object)}, because 
the comparison methods on the timeline
+      * are not always the same as {@code compareTo(…)}.
+      *
+      * @param  <T>    base class of the objects to compare.
+      * @param  test   {@link #BEFORE}, {@link #AFTER} or {@link #EQUAL}.
+      * @param  type   base class of the {@code self} and {@code other} 
arguments.
+      * @param  self   the object on which to invoke the method identified by 
{@code test}.
+      * @param  other  the argument to give to the test method call.
+      * @return the result of performing the comparison identified by {@code 
test}.
 -     * @throws InvalidFilterValueException if the two objects cannot be 
compared.
++     * @throws IllegalArgumentException if the two objects cannot be compared.
+      */
+     static <T> boolean compare(final int test, final Class<T> type, final T 
self, final T other) {
+         /*
+          * The following cast is not strictly true, it should be `<? extends 
T>`.
+          * However, because of the `isInstance(…)` check and because <T> is 
used
+          * only as parameter type (no collection), it is okay to use it that 
way.
+          */
+         final TimeMethods<? super T> tc = findSpecialized(type);
+         if (tc != null) {
+             /*
+              * Found one of the special cases listed in `INTERFACES` or 
`FINAL_TYPE`.
+              * If the other type is compatible, the comparison is executed 
directly.
+              * Note: the `switch` statement is equivalent to 
`tc.compare(test, …)`,
+              * but is inlined because that method is never overridden in this 
context.
+              */
+             if (tc.type.isInstance(other)) {
+                 assert tc.type.isAssignableFrom(type) : tc;     // Those 
types are not necessarily equal.
+                 final BiPredicate<? super T, ? super T> p;
+                 switch (test) {
+                     case BEFORE: p = tc.isBefore; break;
+                     case AFTER:  p = tc.isAfter;  break;
+                     case EQUAL:  p = tc.isEqual;  break;
+                     default: throw new AssertionError(test);
+                 }
+                 return p.test(self, other);
+             }
+         } else if (self instanceof Comparable<?> && type.isInstance(other)) {
+             /*
+              * The type of the first operand is not a special case, but the 
second operand is compatible
+              * for a call to the generic `compareTo(…)` method. This case 
does not happen often, because
+              * not many `java.time` classes have no "is before" or "is after" 
operations.
+              * Some examples are `Month` and `DayOfWeek`.
+              */
+             @SuppressWarnings("unchecked")          // Safe because 
verification done by `isInstance(…)`.
+             final int c = ((Comparable) self).compareTo(other);
+             switch (test) {
+                 case BEFORE: return c <  0;
+                 case AFTER:  return c >  0;
+                 case EQUAL:  return c == 0;
+                 default: throw new AssertionError(test);
+             }
+         }
+         /*
+          * If we reach this point, the two operands are of different classes 
and we cannot compare them directly.
+          * Try to compare the two operands as instants on the timeline.
+          */
+         return compareAsInstants(test, accessor(self), accessor(other));
+     }
+ 
+     /**
+      * Returns the given object as a temporal accessor.
+      */
+     private static TemporalAccessor accessor(final Object value) {
+         if (value instanceof TemporalAccessor) {
+             return (TemporalAccessor) value;
+         } else if (value instanceof Date) {
+             return ((Date) value).toInstant();      // Overridden in `Date` 
subclasses.
+         } else {
 -            throw new InvalidFilterValueException(Errors.format(
++            throw new IllegalArgumentException(Errors.format(
+                     Errors.Keys.CannotCompareInstanceOf_2, value.getClass(), 
TemporalAccessor.class));
+         }
+     }
+ 
+     /**
+      * Compares two temporal objects as instants.
+      * This is a last-resort fallback, when objects cannot be compared by 
their own methods.
+      *
+      * @param  test   {@link #BEFORE}, {@link #AFTER} or {@link #EQUAL}.
+      * @param  self   the object on which to invoke the method identified by 
{@code test}.
+      * @param  other  the argument to give to the test method call.
+      * @return the result of performing the comparison identified by {@code 
test}.
 -     * @throws InvalidFilterValueException if the two objects cannot be 
compared.
++     * @throws IllegalArgumentException if the two objects cannot be compared.
+      */
+     private static boolean compareAsInstants(final int test, final 
TemporalAccessor self, final TemporalAccessor other) {
+         try {
+             long t1 =  self.getLong(ChronoField.INSTANT_SECONDS);
+             long t2 = other.getLong(ChronoField.INSTANT_SECONDS);
+             if (t1 == t2) {
+                 t1 =  self.getLong(ChronoField.NANO_OF_SECOND);     // Should 
be present according Javadoc.
+                 t2 = other.getLong(ChronoField.NANO_OF_SECOND);
+                 if (t1 == t2) {
+                     return test == EQUAL;
+                 }
+             }
+             return test == ((t1 < t2) ? BEFORE : AFTER);
+         } catch (DateTimeException | ArithmeticException e) {
 -            throw new InvalidFilterValueException(Errors.format(
++            throw new IllegalArgumentException(Errors.format(
+                     Errors.Keys.CannotCompareInstanceOf_2, self.getClass(), 
other.getClass()), e);
+         }
+     }
+ 
+     /**
+      * Returns the set of methods that can be invoked on instances of the 
given type, or {@code null} if none.
+      * This method returns only one of the methods defined in {@link 
#FINAL_TYPES} or {@link #INTERFACES}.
+      * It shall not try to create fallbacks.
+      *
+      * @param  <T>   compile-time value of the {@code type} argument.
+      * @param  type  the type of temporal object for which to get specialized 
methods.
+      * @return set of specialized methods for the given object type, or 
{@code null} if none.
+      */
+     @SuppressWarnings("unchecked")
+     private static <T> TimeMethods<? super T> findSpecialized(final Class<T> 
type) {
+         {   // Block for keeping `tc` in local scope.
+             TimeMethods<?> tc = FINAL_TYPES.get(type);
+             if (tc != null) {
+                 assert tc.type == type : tc;
+                 return (TimeMethods<T>) tc;             // Safe because of 
`==` checks.
+             }
+         }
+         for (TimeMethods<?> tc : INTERFACES) {
+             if (tc.type.isAssignableFrom(type)) {
+                 return (TimeMethods<? super T>) tc;     // Safe because of 
`isAssignableFrom(…)` checks.
+             }
+         }
+         return null;
+     }
+ 
+     /**
+      * Returns the set of methods that can be invoked on instances of the 
given type.
+      *
+      * @param  <T>   compile-time value of the {@code type} argument.
+      * @param  type  the type of temporal object for which to get specialized 
methods.
+      * @return set of comparison methods for the given object type.
+      */
+     @SuppressWarnings("unchecked")          // For (Comparable) casts.
+     public static <T> TimeMethods<? super T> find(final Class<T> type) {
+         final TimeMethods<? super T> tc = findSpecialized(type);
+         if (tc != null) {
+             return tc;
+         }
+         if (Modifier.isFinal(type.getModifiers())) {
+             if (Comparable.class.isAssignableFrom(type)) {
+                 return new TimeMethods<>(type,
+                         (self, other) -> ((Comparable) self).compareTo(other) 
< 0,
+                         (self, other) -> ((Comparable) self).compareTo(other) 
> 0,
+                         (self, other) -> ((Comparable) self).compareTo(other) 
== 0);
+             } else {
 -                throw new 
InvalidFilterValueException(Errors.format(Errors.Keys.CannotCompareInstanceOf_2,
 type, type));
++                throw new 
IllegalArgumentException(Errors.format(Errors.Keys.CannotCompareInstanceOf_2, 
type, type));
+             }
+         } else {
+             return fallback(type);
+         }
+     }
+ 
+     /**
+      * Returns the last-resort fallback when the type of temporal objects 
cannot be determined in advance.
+      *
+      * @param  <T>   compile-time value of the {@code type} argument.
+      * @param  type  the type of temporal object for which to get the 
last-resource fallback methods.
+      * @return set of last-resort comparison methods for the given object 
type.
+      */
+     private static <T> TimeMethods<? super T> fallback(final Class<T> type) {
+         return new TimeMethods<>(type,
+                 (self, other) -> compare(BEFORE, type, self, other),
+                 (self, other) -> compare(AFTER,  type, self, other),
+                 (self, other) -> compare(EQUAL,  type, self, other))
+         {
+             @Override public boolean isDynamic() {
+                 return true;
+             }
+             @Override boolean delegate(final int test, final T self, final T 
other) {
+                 return compare(test, type, self, other);
+             }
+         };
+     }
+ 
+     /**
+      * Returns the unique instance for the type after deserialization.
+      * This is needed for avoiding to serialize the lambda functions.
+      *
+      * @return the object to use after deserialization.
+      * @throws ObjectStreamException if the serialized object contains 
invalid data.
+      */
+     private Object readResolve() throws ObjectStreamException {
+         return find(type);
+     }
+ 
+     /**
+      * Operators for all supported temporal types that are interfaces or 
non-final classes.
+      * Those types need to be checked with {@link 
Class#isAssignableFrom(Class)} in iteration order.
+      */
+     @SuppressWarnings({"rawtypes", "unchecked"})            // For `Chrono*` 
interfaces, because they are parameterized.
+     private static final TimeMethods<?>[] INTERFACES = {
+         new TimeMethods<>(ChronoZonedDateTime.class, 
ChronoZonedDateTime::isBefore, ChronoZonedDateTime::isAfter, 
ChronoZonedDateTime::isEqual),
+         new TimeMethods<>(ChronoLocalDateTime.class, 
ChronoLocalDateTime::isBefore, ChronoLocalDateTime::isAfter, 
ChronoLocalDateTime::isEqual),
+         new TimeMethods<>(    ChronoLocalDate.class,     
ChronoLocalDate::isBefore,     ChronoLocalDate::isAfter,     
ChronoLocalDate::isEqual),
+         new TimeMethods<>(               Date.class,                Date::  
before,                Date::  after,                Date::equals)
+     };
+ 
+     /*
+      * 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.
+      */
+ 
+     /**
+      * Operators for all supported temporal types for which there is no need 
to check for subclasses.
+      * Those classes are usually final, except when wanting to intentionally 
ignore all subclasses.
+      * Those types should be tested before {@link #INTERFACES} because this 
check is quick.
+      *
+      * <h4>Implementation note</h4>
+      * {@link Year}, {@link YearMonth}, {@link MonthDay}, {@link LocalTime} 
and {@link Instant}
+      * could be replaced by {@link Comparable}. We nevertheless keep the 
specialized classes in
+      * case the implementations change in the future, and also for 
performance reason, because
+      * the code working on generic {@link Comparable} needs to check for 
special cases again.
+      */
+     private static final Map<Class<?>, TimeMethods<?>> FINAL_TYPES = 
Map.ofEntries(
+         entry(new TimeMethods<>(OffsetDateTime.class, 
OffsetDateTime::isBefore, OffsetDateTime::isAfter, OffsetDateTime::isEqual)),
+         entry(new TimeMethods<>(    OffsetTime.class,     
OffsetTime::isBefore,     OffsetTime::isAfter,     OffsetTime::isEqual)),
+         entry(new TimeMethods<>(     LocalTime.class,      
LocalTime::isBefore,      LocalTime::isAfter,      LocalTime::equals)),
+         entry(new TimeMethods<>(          Year.class,           
Year::isBefore,           Year::isAfter,           Year::equals)),
+         entry(new TimeMethods<>(     YearMonth.class,      
YearMonth::isBefore,      YearMonth::isAfter,      YearMonth::equals)),
+         entry(new TimeMethods<>(      MonthDay.class,       
MonthDay::isBefore,       MonthDay::isAfter,       MonthDay::equals)),
+         entry(new TimeMethods<>(       Instant.class,        
Instant::isBefore,        Instant::isAfter,        Instant::equals)),
+         entry(fallback(Temporal.class)),    // Frequently declared type. 
Intentionally no "instance of" checks.
+         entry(fallback(Object.class)));     // Not a final class, but to be 
used when the declared type is Object.
+ 
+     /**
+      * Helper method for adding entries to the {@link #FINAL_TYPES} map.
+      * Shall be used only for final classes.
+      */
+     private static Map.Entry<Class<?>, TimeMethods<?>> entry(final 
TimeMethods<?> op) {
+         return Map.entry(op.type, op);
+     }
+ 
+     /**
+      * Returns a string representation of this set of operations for 
debugging purposes.
+      *
+      * @return a string representation for debugging purposes.
+      */
+     @Override
+     public String toString() {
+         return Strings.toString(TimeMethods.class, "type", 
type.getSimpleName());
+     }
+ }
diff --cc 
endorsed/src/org.apache.sis.feature/main/org/apache/sis/pending/geoapi/filter/TemporalOperatorName.java
index ddb62b817a,f35ee94813..a30135526f
--- 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/pending/geoapi/filter/TemporalOperatorName.java
+++ 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/pending/geoapi/filter/TemporalOperatorName.java
@@@ -18,11 -18,21 +18,15 @@@ package org.apache.sis.pending.geoapi.f
  
  
  /**
 - * Exception that may be thrown by a portraying operation.
 - *
 - * @author Johann Sorel (Geomatys)
 + * Placeholder for GeoAPI 3.1 interfaces (not yet released).
 + * Shall not be visible in public API, as it will be deleted after next 
GeoAPI release.
   */
 -public class RenderingException extends Exception {
 -
 -    public RenderingException(String message) {
 -        super(message);
 -    }
 -
 -    public RenderingException(Throwable cause) {
 -        super(cause);
 -    }
 +@SuppressWarnings("doclint:missing")
 +public enum TemporalOperatorName {
 +    AFTER, BEFORE, BEGINS, BEGUN_BY, CONTAINS, DURING, EQUALS, OVERLAPS, 
MEETS, ENDS,
 +    OVERLAPPED_BY, MET_BY, ENDED_BY, ANY_INTERACTS;
+ 
 -    public RenderingException(String message, Throwable cause) {
 -        super(message, cause);
++    public String identifier() {
++        return name().toLowerCase();
+     }
  }
diff --cc 
endorsed/src/org.apache.sis.feature/test/org/apache/sis/filter/TemporalFilterTest.java
index 71c23abbd6,b349e62672..a07fd7b129
--- 
a/endorsed/src/org.apache.sis.feature/test/org/apache/sis/filter/TemporalFilterTest.java
+++ 
b/endorsed/src/org.apache.sis.feature/test/org/apache/sis/filter/TemporalFilterTest.java
@@@ -22,12 -24,14 +24,12 @@@ import static org.apache.sis.util.privy
  import org.junit.jupiter.api.Test;
  import static org.junit.jupiter.api.Assertions.*;
  import org.apache.sis.test.TestCase;
- import org.apache.sis.test.TestUtilities;
  import static org.apache.sis.test.Assertions.assertSerializedEquals;
  
 -// Specific to the geoapi-3.1 and geoapi-4.0 branches:
 -import org.opengis.temporal.Period;
 -import org.opengis.feature.Feature;
 -import org.opengis.filter.FilterFactory;
 -import org.opengis.filter.TemporalOperator;
 -import org.opengis.filter.TemporalOperatorName;
 +// Specific to the main branch:
 +import org.apache.sis.feature.AbstractFeature;
++import org.apache.sis.pending.geoapi.temporal.Period;
 +import org.apache.sis.pending.geoapi.filter.TemporalOperatorName;
  
  
  /**
@@@ -40,7 -44,7 +42,7 @@@ public final class TemporalFilterTest e
      /**
       * The factory to use for creating the objects to test.
       */
-     private final DefaultFilterFactory<AbstractFeature,Object,Object> factory;
 -    private FilterFactory<Feature, Object, ? super Period> factory;
++    private DefaultFilterFactory<AbstractFeature, Object, ? super Period> 
factory;
  
      /**
       * The filter to test. This field shall be assigned by each {@code 
testFoo()} method by invoking
diff --cc 
endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/iso/citation/DefaultCitation.java
index b3251941cf,7f06cf9de3..26e877abe8
--- 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/iso/citation/DefaultCitation.java
+++ 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/iso/citation/DefaultCitation.java
@@@ -211,6 -206,7 +211,7 @@@ public class DefaultCitation extends IS
       *
       * @see #castOrCopy(Citation)
       */
 -    @SuppressWarnings({"this-escape", "deprecation"})
++    @SuppressWarnings("this-escape")
      public DefaultCitation(final Citation object) {
          super(object);
          if (object != null) {
diff --cc 
endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/iso/distribution/DefaultStandardOrderProcess.java
index a4e68742e0,2991ced2ec..6689ee1496
--- 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/iso/distribution/DefaultStandardOrderProcess.java
+++ 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/iso/distribution/DefaultStandardOrderProcess.java
@@@ -29,14 -30,8 +30,13 @@@ import org.opengis.metadata.distributio
  import org.apache.sis.xml.bind.gco.GO_RecordType;
  import org.apache.sis.xml.bind.gco.GO_Record;
  import org.apache.sis.metadata.iso.ISOMetadata;
- import static org.apache.sis.metadata.privy.ImplementationHelper.toDate;
- import static 
org.apache.sis.metadata.privy.ImplementationHelper.toMilliseconds;
+ import org.apache.sis.util.privy.TemporalDate;
  
 +// Specific to the main branch:
 +import org.opengis.annotation.UML;
 +import static org.opengis.annotation.Obligation.OPTIONAL;
 +import static org.opengis.annotation.Specification.ISO_19115;
 +
  
  /**
   * Common ways in which the resource may be obtained or received, and related 
instructions
@@@ -134,13 -129,11 +134,13 @@@ public class DefaultStandardOrderProces
          super(object);
          if (object != null) {
              fees                     = object.getFees();
-             plannedAvailableDateTime = 
toMilliseconds(object.getPlannedAvailableDateTime());
+             plannedAvailableDateTime = 
TemporalDate.toTemporal(object.getPlannedAvailableDateTime());
              orderingInstructions     = object.getOrderingInstructions();
              turnaround               = object.getTurnaround();
 -            orderOptionsType         = object.getOrderOptionsType();
 -            orderOptions             = object.getOrderOptions();
 +            if (object instanceof DefaultStandardOrderProcess) {
 +                orderOptionsType = ((DefaultStandardOrderProcess) 
object).getOrderOptionsType();
 +                orderOptions     = ((DefaultStandardOrderProcess) 
object).getOrderOptions();
 +            }
          }
      }
  
diff --cc 
endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/iso/identification/DefaultUsage.java
index 32c7a33efc,fa65552a55..8c6ea0c521
--- 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/iso/identification/DefaultUsage.java
+++ 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/iso/identification/DefaultUsage.java
@@@ -163,15 -159,12 +164,15 @@@ public class DefaultUsage extends ISOMe
          super(object);
          if (object != null) {
              specificUsage             = object.getSpecificUsage();
-             usageDate                 = toMilliseconds(object.getUsageDate());
+             usageDate                 = 
TemporalDate.toTemporal(object.getUsageDate());
              userDeterminedLimitations = object.getUserDeterminedLimitations();
              userContactInfo           = 
copyCollection(object.getUserContactInfo(), ResponsibleParty.class);
 -            responses                 = copyCollection(object.getResponses(), 
InternationalString.class);
 -            additionalDocumentation   = 
copyCollection(object.getAdditionalDocumentation(), Citation.class);
 -            identifiedIssues          = 
copyCollection(object.getIdentifiedIssues(), Citation.class);
 +            if (object instanceof DefaultUsage) {
 +                final DefaultUsage c = (DefaultUsage) object;
 +                responses                 = copyCollection(c.getResponses(), 
InternationalString.class);
 +                additionalDocumentation   = 
copyCollection(c.getAdditionalDocumentation(), Citation.class);
 +                identifiedIssues          = 
copyCollection(c.getIdentifiedIssues(), Citation.class);
 +            }
          }
      }
  
diff --cc 
endorsed/src/org.apache.sis.metadata/main/org/apache/sis/pending/temporal/DefaultPeriod.java
index ce43f62a4b,6f4cff5259..afc79c7459
--- 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/pending/temporal/DefaultPeriod.java
+++ 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/pending/temporal/DefaultPeriod.java
@@@ -17,10 -17,12 +17,10 @@@
  package org.apache.sis.pending.temporal;
  
  import java.util.Objects;
- import java.time.Instant;
+ import java.time.temporal.Temporal;
  
 -// Specific to the geoapi-3.1 and geoapi-4.0 branches:
 -import java.time.Duration;
 -import java.time.temporal.TemporalAmount;
 -import org.opengis.temporal.Period;
 +// Specific to the main branch:
 +import org.apache.sis.pending.geoapi.temporal.Period;
  
  
  /**
@@@ -29,12 -31,12 +29,12 @@@
   *
   * @author  Martin Desruisseaux (Geomatys)
   */
- final class DefaultPeriod implements Period {
 -public final class DefaultPeriod extends Primitive implements Period {
++public final class DefaultPeriod implements Period {
      /** Bounds making this period. */
-     private final Instant beginning, ending;
+     private final Temporal beginning, ending;
  
      /** Creates a new period with the given bounds. */
-     DefaultPeriod(final Instant beginning, final Instant ending) {
+     public DefaultPeriod(final Temporal beginning, final Temporal ending) {
          this.beginning = beginning;
          this.ending    = ending;
      }
diff --cc 
endorsed/src/org.apache.sis.referencing/test/org/apache/sis/test/integration/MetadataTest.java
index 06fcd20859,a3a48f2b93..7505b27228
--- 
a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/test/integration/MetadataTest.java
+++ 
b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/test/integration/MetadataTest.java
@@@ -154,9 -142,10 +153,9 @@@ public final class MetadataTest extend
              final var citation = new DefaultCitation("Some set of points");
              citation.setAlternateTitles(Set.of(new 
SimpleInternationalString("Code XYZ")));
              citation.setDates(List.of(
-                     new DefaultCitationDate(TestUtilities.date("1990-06-04 
22:00:00"), DateType.REVISION),
-                     new DefaultCitationDate(TestUtilities.date("1979-08-02 
22:00:00"), DateType.CREATION)));
+                     new DefaultCitationDate(LocalDate.of(1990, 6, 5), 
DateType.REVISION),
+                     new DefaultCitationDate(LocalDate.of(1979, 8, 3), 
DateType.CREATION)));
              {
 -                @SuppressWarnings("deprecation")
                  final var originator = new 
DefaultResponsibleParty(Role.ORIGINATOR);
                  final var online = new 
DefaultOnlineResource(URI.create("http://www.com.univ-mrs.fr/LOB/";));
                  online.setProtocol(Constants.HTTP);
@@@ -222,10 -212,11 +221,10 @@@
                  final var aggregateInfo = new DefaultAggregateInformation();
                  final var name = new DefaultCitation("Some oceanographic 
campaign");
                  name.setAlternateTitles(Set.of(new 
SimpleInternationalString("Pseudo group of data")));
-                 name.setDates(Set.of(new 
DefaultCitationDate(TestUtilities.date("1990-06-04 22:00:00"), 
DateType.REVISION)));
+                 name.setDates(Set.of(new 
DefaultCitationDate(LocalDate.of(1990, 6, 5), DateType.REVISION)));
                  aggregateInfo.setName(name);
                  aggregateInfo.setInitiativeType(InitiativeType.CAMPAIGN);
 -                
aggregateInfo.setAssociationType(AssociationType.LARGER_WORK_CITATION);
 +                
aggregateInfo.setAssociationType(AssociationType.LARGER_WORD_CITATION); // 
There is a typo ("WORD" → "WORK"), but we have to use the wrong spelling for 
this branch.
                  identification.setAssociatedResources(Set.of(aggregateInfo));
              }
              /*
@@@ -380,11 -373,8 +380,9 @@@
                       "<gmx:Anchor xlink:href=\"SDN:L231:3:CDI\">Pseudo Common 
Data Index record</gmx:Anchor>");
          replace(xml, "<gcol:CharacterString>4326</gcol:CharacterString>",
                       "<gmx:Anchor 
xlink:href=\"SDN:L101:2:4326\">4326</gmx:Anchor>");
 +        replace(xml, "License", "Licence");
          /*
-          * The <gmd:EX_TemporalExtent> block cannot be marshalled es expected 
yet (need a "sis-temporal" module).
-          * We need to instruct the XML comparator to ignore this block during 
the comparison. We also ignore for
-          * now the "gml:id" attribute since SIS generates different values 
than the ones in our test XML file,
+          * Ignore the "gml:id" attribute because SIS generates different 
values than the ones in our test XML file,
           * and those values may change in future SIS version.
           */
          final var comparator = new DocumentComparator(getResource(), 
xml.toString());
diff --cc 
endorsed/src/org.apache.sis.referencing/test/org/apache/sis/test/integration/MetadataVerticalTest.java
index d6701022c7,949b1c0a2d..56863a6c3b
--- 
a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/test/integration/MetadataVerticalTest.java
+++ 
b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/test/integration/MetadataVerticalTest.java
@@@ -87,10 -88,10 +89,10 @@@ public final class MetadataVerticalTes
      @Test
      public void testMetadataWithVerticalCRS() throws JAXBException {
          final Metadata metadata = unmarshalFile(Metadata.class, 
openTestFile());
-         assertEquals("20090901",                     
metadata.getFileIdentifier());
-         assertEquals(Locale.ENGLISH,                 metadata.getLanguage());
-         assertEquals(CharacterSet.UTF_8,             
metadata.getCharacterSet());
-         assertEquals(xmlDate("2014-01-04 00:00:00"), metadata.getDateStamp());
 -        assertEquals("20090901",               
metadata.getMetadataIdentifier().getCode());
 -        assertEquals(Locale.ENGLISH,           
getSingleton(metadata.getLocalesAndCharsets().keySet()));
 -        assertEquals(StandardCharsets.UTF_8,   
getSingleton(metadata.getLocalesAndCharsets().values()));
 -        assertEquals(LocalDate.of(2014, 1, 4), 
TemporalDate.toTemporal(getSingleton(metadata.getDateInfo()).getDate()));
++        assertEquals("20090901",               metadata.getFileIdentifier());
++        assertEquals(Locale.ENGLISH,           metadata.getLanguage());
++        assertEquals(CharacterSet.UTF_8,       metadata.getCharacterSet());
++        assertEquals(LocalDate.of(2014, 1, 4), 
TemporalDate.toTemporal(metadata.getDateStamp()));
          /*
           * <gmd:contact>
           *   <gmd:CI_ResponsibleParty>
diff --cc 
endorsed/src/org.apache.sis.util/main/org/apache/sis/pending/geoapi/temporal/Period.java
index 9187bc9c74,a6eeffe0b8..f8ccb863ff
--- 
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/pending/geoapi/temporal/Period.java
+++ 
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/pending/geoapi/temporal/Period.java
@@@ -14,31 -14,32 +14,31 @@@
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
 -package org.apache.sis.xml.bind.referencing;
 +package org.apache.sis.pending.geoapi.temporal;
  
- import java.time.Instant;
 -import org.opengis.referencing.datum.VerticalDatumType;
 -import org.apache.sis.xml.bind.gml.CodeListAdapter;
++import java.time.temporal.Temporal;
 +import org.opengis.temporal.TemporalPrimitive;
  
  
  /**
 - * JAXB adapter for (un)marshalling of GeoAPI code list.
 + * Placeholder for a GeoAPI interfaces not present in GeoAPI 3.0.
   *
   * @author  Martin Desruisseaux (Geomatys)
 + * @since   0.3
 + * @version 1.5
   */
 -@SuppressWarnings("deprecation")
 -public final class CD_VerticalDatumType extends 
CodeListAdapter<VerticalDatumType> {
 +public interface Period extends TemporalPrimitive {
      /**
 -     * Empty constructor for JAXB only.
 +     * Links this period to the instant at which it ends.
 +     *
 +     * @return The beginning instant.
       */
-     Instant getBeginning();
 -    public CD_VerticalDatumType() {
 -    }
++    Temporal getBeginning();
  
      /**
 -     * {@inheritDoc}
 +     * Links this period to the instant at which it ends.
       *
 -     * @return {@code VerticalDatumType.class}
 +     * @return The end instant.
       */
-     Instant getEnding();
 -    @Override
 -    protected Class<VerticalDatumType> getCodeListClass() {
 -        return VerticalDatumType.class;
 -    }
++    Temporal getEnding();
  }
diff --cc 
optional/src/org.apache.sis.gui/main/org/apache/sis/gui/metadata/IdentificationInfo.java
index 7a32422577,08a6632288..e5617a1c59
--- 
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/metadata/IdentificationInfo.java
+++ 
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/metadata/IdentificationInfo.java
@@@ -363,9 -364,9 +362,9 @@@ final class IdentificationInfo extends 
           */
          text = null;
          Identifier identifier = null;
-         Range<Instant> timeRange = null;
+         Range<Date> timeRange = null;
          Range<Double> heights = null;
 -        for (final Extent extent : nonNull(info.getExtents())) {
 +        for (final Extent extent : nonNull(dataInfo != null ? 
dataInfo.getExtents() : null)) {
              if (extent != null) {
                  if (text == null) {
                      text = owner.string(extent.getDescription());


Reply via email to