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: Better handling of temporal types in comparisons.
Date Fri, 23 Aug 2019 12:56:51 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 c51c8cc  Better handling of temporal types in comparisons.
c51c8cc is described below

commit c51c8cc6bc4913bd9d4122d9c45f1d0e2a647414
Author: Martin Desruisseaux <martin.desruisseaux@geomatys.com>
AuthorDate: Fri Aug 23 14:56:23 2019 +0200

    Better handling of temporal types in comparisons.
---
 .../org/apache/sis/filter/ComparisonFunction.java  | 337 +++++++++++++++++----
 1 file changed, 270 insertions(+), 67 deletions(-)

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 179dc3e..9e2f78e 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
@@ -21,8 +21,17 @@ import java.math.BigInteger;
 import java.util.Date;
 import java.util.Calendar;
 import java.time.Instant;
+import java.time.LocalTime;
+import java.time.OffsetTime;
+import java.time.LocalDateTime;
 import java.time.OffsetDateTime;
+import java.time.ZonedDateTime;
+import java.time.ZoneId;
 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 org.apache.sis.math.Fraction;
 import org.apache.sis.util.ArgumentChecks;
 
@@ -43,6 +52,11 @@ import org.opengis.filter.FilterVisitor;
  * Null elements in the collection (not to be confused with null operands) are ignored.
  * If both operands are collections, current implementation returns {@code false}.</p>
  *
+ * <p>Comparisons between temporal objects are done with {@code isBefore(…)} or {@code
isAfter(…)} methods when they
+ * have a different semantic than the {@code compareTo(…)} methods. If the two temporal
objects are not of the same
+ * type, only the fields that are common two both types are compared. For example comparison
between {@code LocalDate}
+ * and {@code LocalDateTime} ignores the time fields.</p>
+ *
  * <p>Comparisons of numerical types shall be done by overriding one of the {@code
applyAs…} methods and
  * returning 0 if {@code false} or 1 if {@code true}. Comparisons of other types is done
by overriding
  * the {@code compare(…)} methods.</p>
@@ -189,14 +203,87 @@ abstract class ComparisonFunction extends BinaryFunction implements
BinaryCompar
      * @param  right  the second object to compare. Must be non-null.
      */
     @SuppressWarnings("null")
-    private boolean evaluate(final Object left, final Object right) {
-        if (left instanceof Number) {
-            if (right instanceof Number) {
-                final Number r = apply((Number) left, (Number) right);
-                if (r != null) return r.intValue() != 0;
+    private boolean evaluate(Object left, Object right) {
+        /*
+         * For numbers, the apply(…) method inherited from parent class will delegate to
specialized methods like
+         * applyAsDouble(…). All implementations of those specialized methods in ComparisonFunction
return integer,
+         * so call to intValue() will not cause information lost.
+         */
+        if (left instanceof Number && right instanceof Number) {
+            final Number r = apply((Number) left, (Number) right);
+            if (r != null) return r.intValue() != 0;
+        }
+        /*
+         * For legacy java.util.Date, the compareTo(…) method is consistent only for dates
of the same class.
+         * Otherwise A.compareTo(B) and B.compareTo(A) are inconsistent if one object is
a java.util.Date and
+         * the other object is a java.sql.Timestamp. In such case, we compare the dates as
java.time objects.
+         */
+        if (left instanceof Date && right instanceof Date) {
+            if (left.getClass() == right.getClass()) {
+                return fromCompareTo(((Date) left).compareTo((Date) right));
+            }
+            left  = fromLegacy((Date) left);
+            right = fromLegacy((Date) right);
+        }
+        /*
+         * Temporal objects have complex conversion rules. We take Instant as the most accurate
and unambiguous type.
+         * So if at least one value is an Instant, try to unconditionally promote the other
value to an Instant too.
+         * This conversion will fail if the other object has some undefined fields; for example
java.sql.Date has no
+         * time fields (we do not assume that the values of those fields are zero).
+         *
+         * OffsetTime and OffsetDateTime are final classes that do not implement a java.time.chrono
interface.
+         * Note that OffsetDateTime is convertible into OffsetTime by dropping the date fields,
but we do not
+         * (for now) perform comparaisons that would ignore the date fields of an operand.
+         */
+        if (left instanceof Temporal || right instanceof Temporal) {        // Use || because
an operand may be Date.
+            if (left instanceof Instant) {
+                final Instant t = toInstant(right);
+                if (t != null) return fromCompareTo(((Instant) left).compareTo(t));
+            } else if (right instanceof Instant) {
+                final Instant t = toInstant(left);
+                if (t != null) return fromCompareTo(t.compareTo((Instant) right));
+            } else if (left instanceof OffsetDateTime) {
+                final OffsetDateTime t = toOffsetDateTime(right);
+                if (t != null) return compare((OffsetDateTime) left, t);
+            } else if (right instanceof OffsetDateTime) {
+                final OffsetDateTime t = toOffsetDateTime(left);
+                if (t != null) return compare(t, (OffsetDateTime) right);
+            } else if (left instanceof OffsetTime && right instanceof OffsetTime)
{
+                return compare((OffsetTime) left, (OffsetTime) right);
+            }
+            /*
+             * Comparisons of temporal objects implementing java.time.chrono interfaces.
We need to check the most
+             * complete types first. If the type are different, we reduce to the type of
the less smallest operand.
+             * For example if an operand is a date+time and the other operand is only a date,
then the time fields
+             * will be ignored and a warning will be reported.
+             */
+            if (left instanceof ChronoLocalDateTime<?>) {
+                final ChronoLocalDateTime<?> t = toLocalDateTime(right);
+                if (t != null) return compare((ChronoLocalDateTime<?>) left, t);
+            } else if (right instanceof ChronoLocalDateTime<?>) {
+                final ChronoLocalDateTime<?> t = toLocalDateTime(left);
+                if (t != null) return compare(t, (ChronoLocalDateTime<?>) right);
+            }
+            if (left instanceof ChronoLocalDate) {
+                final ChronoLocalDate t = toLocalDate(right);
+                if (t != null) return compare((ChronoLocalDate) left, t);
+            } else if (right instanceof ChronoLocalDate) {
+                final ChronoLocalDate t = toLocalDate(left);
+                if (t != null) return compare(t, (ChronoLocalDate) right);
+            }
+            if (left instanceof LocalTime) {
+                final LocalTime t = toLocalTime(right);
+                if (t != null) return fromCompareTo(((LocalTime) left).compareTo(t));
+            } else if (right instanceof LocalTime) {
+                final LocalTime t = toLocalTime(left);
+                if (t != null) return fromCompareTo(t.compareTo((LocalTime) right));
             }
-            return false;       // Incompatible types.
         }
+        /*
+         * Test character strings only after all specialized types have been tested. The
intent is that if an
+         * object implements both CharSequence and a specialized interface, they have been
compared as value
+         * objects before to be compared as strings.
+         */
         if (left instanceof CharSequence || right instanceof CharSequence) {            //
Really ||, not &&.
             final String s1 = left.toString();
             final String s2 = right.toString();
@@ -209,29 +296,6 @@ abstract class ComparisonFunction extends BinaryFunction implements BinaryCompar
             return fromCompareTo(result);
         }
         /*
-         * Temporal objects. They have somewhat complex conversions.
-         */
-        if (left instanceof Instant) {
-            final Instant t = toInstant(right);
-            if (t != null) return compare((Instant) left, t);
-        } else if (right instanceof Instant) {
-            final Instant t = toInstant(left);
-            if (t != null) return compare(t, (Instant) right);
-        }
-        if (left instanceof OffsetDateTime && right instanceof OffsetDateTime) {
-            return compare((OffsetDateTime) left, (OffsetDateTime) right);
-        }
-        if (left instanceof ChronoLocalDate) {
-            final ChronoLocalDate t = toLocalDate(right);
-            if (t != null) return compare((ChronoLocalDate) left, t);
-        } else if (right instanceof ChronoLocalDate) {
-            final ChronoLocalDate t = toLocalDate(left);
-            return (t != null) && compare(t, (ChronoLocalDate) right);
-        }
-        if (left instanceof Date && right instanceof Date) {
-            return compare((Date) left, (Date) right);
-        }
-        /*
          * Comparison using `compareTo` method should be last because it does not take in
account
          * the `isMatchingCase` flag and because the semantic is different than < or >
comparator
          * for numbers and dates.
@@ -241,10 +305,30 @@ abstract class ComparisonFunction extends BinaryFunction implements
BinaryCompar
             final int result = ((Comparable) left).compareTo(right);
             return fromCompareTo(result);
         }
+        // TODO: report a warning for non-comparable objects.
         return false;
     }
 
     /**
+     * Converts a legacy {@code Date} object to an object from the {@link java.time} package.
+     * We performs this conversion before to compare to {@code Date} instances that are not
of
+     * the same class, because the {@link Date#compareTo(Date)} method in such case is not
well
+     * defined.
+     */
+    private static Temporal fromLegacy(final Date value) {
+        if (value instanceof java.sql.Timestamp) {
+            return ((java.sql.Timestamp) value).toLocalDateTime();
+        } else if (value instanceof java.sql.Date) {
+            return ((java.sql.Date) value).toLocalDate();
+        } else if (value instanceof java.sql.Time) {
+            return ((java.sql.Time) value).toLocalTime();
+        } else {
+            // Implementation of above toFoo() methods use system default time zone.
+            return LocalDateTime.ofInstant(value.toInstant(), ZoneId.systemDefault());
+        }
+    }
+
+    /**
      * Converts the given object to an {@link Instant}, or returns {@code null} if unconvertible.
      * 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}.
@@ -254,11 +338,18 @@ abstract class ComparisonFunction extends BinaryFunction implements
BinaryCompar
             return (Instant) value;
         } else if (value instanceof OffsetDateTime) {
             return ((OffsetDateTime) value).toInstant();
+        } else if (value instanceof ChronoZonedDateTime) {
+            return ((ChronoZonedDateTime) value).toInstant();
         } else if (value instanceof Date) {
-            if (value instanceof java.sql.Date) {
-                return Instant.ofEpochMilli(((java.sql.Date) value).getTime());
-            } else if (!(value instanceof java.sql.Time)) {
-                return ((Date) value).toInstant();              // Not allowed on java.sql.Date/Time.
+            try {
+                return ((Date) value).toInstant();
+            } catch (UnsupportedOperationException e) {
+                /*
+                 * java.sql.Date and java.sql.Time can not be converted to Instant because
a part
+                 * of their coordinates on the timeline is undefined.  For example in the
case of
+                 * java.sql.Date the hours, minutes and seconds are unspecified (which is
not the
+                 * same thing than assuming that those values are zero).
+                 */
             }
         } else if (value instanceof Calendar) {
             return ((Calendar) value).toInstant();
@@ -267,12 +358,56 @@ abstract class ComparisonFunction extends BinaryFunction implements
BinaryCompar
     }
 
     /**
+     * Converts the given object to an {@link OffsetDateTime}, or returns {@code null} if
unconvertible.
+     */
+    private static OffsetDateTime toOffsetDateTime(final Object value) {
+        if (value instanceof OffsetDateTime) {
+            return (OffsetDateTime) value;
+        } else if (value instanceof ZonedDateTime) {
+            return ((ZonedDateTime) value).toOffsetDateTime();
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Converts the given object to a {@link ChronoLocalDateTime}, or returns {@code null}
if unconvertible.
+     * This method handles the case of legacy SQL {@link java.sql.Timestamp} objects.
+     * Conversion may lost timezone information.
+     */
+    private static ChronoLocalDateTime<?> toLocalDateTime(final Object value) {
+        if (value instanceof ChronoLocalDateTime<?>) {
+            return (ChronoLocalDateTime<?>) value;
+        } else if (value instanceof ChronoZonedDateTime) {
+            ignoringField(ChronoField.OFFSET_SECONDS);
+            return ((ChronoZonedDateTime) value).toLocalDateTime();
+        } else if (value instanceof OffsetDateTime) {
+            ignoringField(ChronoField.OFFSET_SECONDS);
+            return ((OffsetDateTime) value).toLocalDateTime();
+        } else if (value instanceof java.sql.Timestamp) {
+            return ((java.sql.Timestamp) value).toLocalDateTime();
+        } else {
+            return null;
+        }
+    }
+
+    /**
      * Converts the given object to a {@link ChronoLocalDate}, or returns {@code null} if
unconvertible.
      * This method handles the case of legacy SQL {@link java.sql.Date} objects.
+     * Conversion may lost timezone information and time fields.
      */
     private static ChronoLocalDate toLocalDate(final Object value) {
         if (value instanceof ChronoLocalDate) {
             return (ChronoLocalDate) value;
+        } else if (value instanceof ChronoLocalDateTime) {
+            ignoringField(ChronoField.SECOND_OF_DAY);
+            return ((ChronoLocalDateTime) value).toLocalDate();
+        } else if (value instanceof ChronoZonedDateTime) {
+            ignoringField(ChronoField.SECOND_OF_DAY);
+            return ((ChronoZonedDateTime) value).toLocalDate();
+        } else if (value instanceof OffsetDateTime) {
+            ignoringField(ChronoField.SECOND_OF_DAY);
+            return ((OffsetDateTime) value).toLocalDate();
         } else if (value instanceof java.sql.Date) {
             return ((java.sql.Date) value).toLocalDate();
         } else {
@@ -281,10 +416,45 @@ abstract class ComparisonFunction extends BinaryFunction implements
BinaryCompar
     }
 
     /**
+     * Converts the given object to a {@link LocalTime}, or returns {@code null} if unconvertible.
+     * This method handles the case of legacy SQL {@link java.sql.Time} objects.
+     * Conversion may lost timezone information.
+     */
+    private static LocalTime toLocalTime(final Object value) {
+        if (value instanceof LocalTime) {
+            return (LocalTime) value;
+        } else if (value instanceof OffsetTime) {
+            ignoringField(ChronoField.OFFSET_SECONDS);
+            return ((OffsetTime) value).toLocalTime();
+        } else if (value instanceof java.sql.Time) {
+            return ((java.sql.Time) value).toLocalTime();
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Invoked when a conversion cause a field to be ignored. For example if a "date+time"
object is compared
+     * with a "date" object, the "time" field is ignored. Expected values are:
+     *
+     * <ul>
+     *   <li>{@link ChronoField#OFFSET_SECONDS}: time zone is ignored.</li>
+     *   <li>{@link ChronoField#SECOND_OF_DAY}:  time of dat and time zone are ignored.</li>
+     * </ul>
+     *
+     * @param  field  the field which is ignored.
+     *
+     * @see <a href="https://issues.apache.org/jira/browse/SIS-460">SIS-460</a>
+     */
+    private static void ignoringField(final ChronoField field) {
+        // TODO
+    }
+
+    /**
      * Converts the boolean result as an integer for use as a return value of the {@code
applyAs…} methods.
      * This is a helper class for subclasses.
      */
-    static Number number(final boolean result) {
+    private static Number number(final boolean result) {
         return result ? 1 : 0;
     }
 
@@ -294,18 +464,37 @@ abstract class ComparisonFunction extends BinaryFunction implements
BinaryCompar
     protected abstract boolean fromCompareTo(int result);
 
     /**
-     * Compares two dates with time-zone information.
+     * Compares two times with time-zone information. Implementations shall not use {@code
compareTo(…)} because
+     * that method compares more information than desired in order to ensure consistency
with {@code equals(…)}.
+     */
+    protected abstract boolean compare(OffsetTime left, OffsetTime right);
+
+    /**
+     * Compares two dates with time-zone information. Implementations shall not use {@code
compareTo(…)} because
+     * that method compares more information than desired in order to ensure consistency
with {@code equals(…)}.
      */
     protected abstract boolean compare(OffsetDateTime left, OffsetDateTime right);
 
     /**
-     * Compares two dates without time-of-day and time-zone information.
+     * Compares two dates without time-of-day and time-zone information. Implementations
shall not use
+     * {@code compareTo(…)} because that method also compares chronology, which is not
desired for the
+     * purpose of "is before" or "is after" comparison functions.
      */
     protected abstract boolean compare(ChronoLocalDate left, ChronoLocalDate right);
 
-    /** Compares two instantaneous points on the time-line. */
-    protected boolean compare(Date    left, Date    right) {return fromCompareTo(left.compareTo(right));}
-    protected boolean compare(Instant left, Instant right) {return fromCompareTo(left.compareTo(right));}
+    /**
+     * Compares two dates without time-zone information. Implementations shall not use {@code
compareTo(…)}
+     * because that method also compares chronology, which is not desired for the purpose
of "is before" or
+     * "is after" comparison functions.
+     */
+    protected abstract boolean compare(ChronoLocalDateTime<?> left, ChronoLocalDateTime<?>
right);
+
+    /**
+     * Compares two dates with time-zone information. Implementations shall not use {@code
compareTo(…)}
+     * because that method also compares chronology, which is not desired for the purpose
of "is before"
+     * or "is after" comparison functions.
+     */
+    protected abstract boolean compare(ChronoZonedDateTime<?> left, ChronoZonedDateTime<?>
right);
 
     /** Delegates to {@link BigDecimal#compareTo(BigDecimal)} and interprets the result with
{@link #fromCompareTo(int)}. */
     @Override protected final Number applyAsDecimal (BigDecimal left, BigDecimal right) {return
number(fromCompareTo(left.compareTo(right)));}
@@ -333,12 +522,13 @@ abstract class ComparisonFunction extends BinaryFunction implements
BinaryCompar
         @Override protected boolean fromCompareTo(final int result) {return result < 0;}
 
         /** Performs the comparison and returns the result as 0 (false) or 1 (true). */
-        @Override protected Number  applyAsDouble(double          left, double          right)
{return number(left < right);}
-        @Override protected Number  applyAsLong  (long            left, long            right)
{return number(left < right);}
-        @Override protected boolean compare      (Date            left, Date            right)
{return left.  before(right);}
-        @Override protected boolean compare      (Instant         left, Instant         right)
{return left.isBefore(right);}
-        @Override protected boolean compare      (OffsetDateTime  left, OffsetDateTime  right)
{return left.isBefore(right);}
-        @Override protected boolean compare      (ChronoLocalDate left, ChronoLocalDate right)
{return left.isBefore(right);}
+        @Override protected Number  applyAsDouble(double                 left, double   
             right) {return number(left < right);}
+        @Override protected Number  applyAsLong  (long                   left, long     
             right) {return number(left < right);}
+        @Override protected boolean compare      (OffsetTime             left, OffsetTime
            right) {return left.isBefore(right);}
+        @Override protected boolean compare      (OffsetDateTime         left, OffsetDateTime
        right) {return left.isBefore(right);}
+        @Override protected boolean compare      (ChronoLocalDate        left, ChronoLocalDate
       right) {return left.isBefore(right);}
+        @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. */
         @Override public Object accept(FilterVisitor visitor, Object extraData) {
@@ -367,10 +557,13 @@ abstract class ComparisonFunction extends BinaryFunction implements
BinaryCompar
         @Override protected boolean fromCompareTo(final int result) {return result <=
0;}
 
         /** Performs the comparison and returns the result as 0 (false) or 1 (true). */
-        @Override protected Number  applyAsDouble(double          left, double          right)
{return number(left <= right);}
-        @Override protected Number  applyAsLong  (long            left, long            right)
{return number(left <= right);}
-        @Override protected boolean compare      (OffsetDateTime  left, OffsetDateTime  right)
{return left.isBefore(right) || left.isEqual(right);}
-        @Override protected boolean compare      (ChronoLocalDate left, ChronoLocalDate right)
{return left.isBefore(right) || left.isEqual(right);}
+        @Override protected Number  applyAsDouble(double                 left, double   
             right) {return number(left <= right);}
+        @Override protected Number  applyAsLong  (long                   left, long     
             right) {return number(left <= right);}
+        @Override protected boolean compare      (OffsetTime             left, OffsetTime
            right) {return !left.isAfter(right);}
+        @Override protected boolean compare      (OffsetDateTime         left, OffsetDateTime
        right) {return !left.isAfter(right);}
+        @Override protected boolean compare      (ChronoLocalDate        left, ChronoLocalDate
       right) {return !left.isAfter(right);}
+        @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. */
         @Override public Object accept(FilterVisitor visitor, Object extraData) {
@@ -399,12 +592,13 @@ abstract class ComparisonFunction extends BinaryFunction implements
BinaryCompar
         @Override protected boolean fromCompareTo(final int result) {return result > 0;}
 
         /** Performs the comparison and returns the result as 0 (false) or 1 (true). */
-        @Override protected Number  applyAsDouble(double          left, double          right)
{return number(left > right);}
-        @Override protected Number  applyAsLong  (long            left, long            right)
{return number(left > right);}
-        @Override protected boolean compare      (Date            left, Date            right)
{return left.  after(right);}
-        @Override protected boolean compare      (Instant         left, Instant         right)
{return left.isAfter(right);}
-        @Override protected boolean compare      (OffsetDateTime  left, OffsetDateTime  right)
{return left.isAfter(right);}
-        @Override protected boolean compare      (ChronoLocalDate left, ChronoLocalDate right)
{return left.isAfter(right);}
+        @Override protected Number  applyAsDouble(double                 left, double   
             right) {return number(left > right);}
+        @Override protected Number  applyAsLong  (long                   left, long     
             right) {return number(left > right);}
+        @Override protected boolean compare      (OffsetTime             left, OffsetTime
            right) {return left.isAfter(right);}
+        @Override protected boolean compare      (OffsetDateTime         left, OffsetDateTime
        right) {return left.isAfter(right);}
+        @Override protected boolean compare      (ChronoLocalDate        left, ChronoLocalDate
       right) {return left.isAfter(right);}
+        @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. */
         @Override public Object accept(FilterVisitor visitor, Object extraData) {
@@ -433,10 +627,13 @@ abstract class ComparisonFunction extends BinaryFunction implements
BinaryCompar
         @Override protected boolean fromCompareTo(final int result) {return result >=
0;}
 
         /** Performs the comparison and returns the result as 0 (false) or 1 (true). */
-        @Override protected Number  applyAsDouble(double          left, double          right)
{return number(left >= right);}
-        @Override protected Number  applyAsLong  (long            left, long            right)
{return number(left >= right);}
-        @Override protected boolean compare      (OffsetDateTime  left, OffsetDateTime  right)
{return left.isAfter(right) || left.isEqual(right);}
-        @Override protected boolean compare      (ChronoLocalDate left, ChronoLocalDate right)
{return left.isAfter(right) || left.isEqual(right);}
+        @Override protected Number  applyAsDouble(double                 left, double   
             right) {return number(left >= right);}
+        @Override protected Number  applyAsLong  (long                   left, long     
             right) {return number(left >= right);}
+        @Override protected boolean compare      (OffsetTime             left, OffsetTime
            right) {return !left.isBefore(right);}
+        @Override protected boolean compare      (OffsetDateTime         left, OffsetDateTime
        right) {return !left.isBefore(right);}
+        @Override protected boolean compare      (ChronoLocalDate        left, ChronoLocalDate
       right) {return !left.isBefore(right);}
+        @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. */
         @Override public Object accept(FilterVisitor visitor, Object extraData) {
@@ -465,10 +662,13 @@ abstract class ComparisonFunction extends BinaryFunction implements
BinaryCompar
         @Override protected boolean fromCompareTo(final int result) {return result == 0;}
 
         /** Performs the comparison and returns the result as 0 (false) or 1 (true). */
-        @Override protected Number  applyAsDouble(double          left, double          right)
{return number(left == right);}
-        @Override protected Number  applyAsLong  (long            left, long            right)
{return number(left == right);}
-        @Override protected boolean compare      (OffsetDateTime  left, OffsetDateTime  right)
{return left.isEqual(right);}
-        @Override protected boolean compare      (ChronoLocalDate left, ChronoLocalDate right)
{return left.isEqual(right);}
+        @Override protected Number  applyAsDouble(double                 left, double   
             right) {return number(left == right);}
+        @Override protected Number  applyAsLong  (long                   left, long     
             right) {return number(left == right);}
+        @Override protected boolean compare      (OffsetTime             left, OffsetTime
            right) {return left.isEqual(right);}
+        @Override protected boolean compare      (OffsetDateTime         left, OffsetDateTime
        right) {return left.isEqual(right);}
+        @Override protected boolean compare      (ChronoLocalDate        left, ChronoLocalDate
       right) {return left.isEqual(right);}
+        @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. */
         @Override public Object accept(FilterVisitor visitor, Object extraData) {
@@ -497,10 +697,13 @@ abstract class ComparisonFunction extends BinaryFunction implements
BinaryCompar
         @Override protected boolean fromCompareTo(final int result) {return result != 0;}
 
         /** Performs the comparison and returns the result as 0 (false) or 1 (true). */
-        @Override protected Number  applyAsDouble(double          left, double          right)
{return number(left != right);}
-        @Override protected Number  applyAsLong  (long            left, long            right)
{return number(left != right);}
-        @Override protected boolean compare      (OffsetDateTime  left, OffsetDateTime  right)
{return !left.isEqual(right);}
-        @Override protected boolean compare      (ChronoLocalDate left, ChronoLocalDate right)
{return !left.isEqual(right);}
+        @Override protected Number  applyAsDouble(double                 left, double   
             right) {return number(left != right);}
+        @Override protected Number  applyAsLong  (long                   left, long     
             right) {return number(left != right);}
+        @Override protected boolean compare      (OffsetTime             left, OffsetTime
            right) {return !left.isEqual(right);}
+        @Override protected boolean compare      (OffsetDateTime         left, OffsetDateTime
        right) {return !left.isEqual(right);}
+        @Override protected boolean compare      (ChronoLocalDate        left, ChronoLocalDate
       right) {return !left.isEqual(right);}
+        @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. */
         @Override public Object accept(FilterVisitor visitor, Object extraData) {


Mime
View raw message