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 9b2fe86  `RangeFormat` should accept ranges of objects from the 
`java.time` package (at lest the main types).
9b2fe86 is described below

commit 9b2fe865ae3c2a64d588084b00c0ef679b04cbb3
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Wed Mar 17 00:06:56 2021 +0100

    `RangeFormat` should accept ranges of objects from the `java.time` package 
(at lest the main types).
---
 .../sis/internal/util/StandardDateFormat.java      | 39 ++++++++++++++++++-
 .../main/java/org/apache/sis/measure/Range.java    |  2 +-
 .../java/org/apache/sis/measure/RangeFormat.java   | 38 ++++++++++++++++---
 .../org/apache/sis/measure/RangeFormatTest.java    | 44 +++++++++++++++++++++-
 .../java/org/apache/sis/measure/RangeTest.java     | 16 +++++++-
 5 files changed, 128 insertions(+), 11 deletions(-)

diff --git 
a/core/sis-utility/src/main/java/org/apache/sis/internal/util/StandardDateFormat.java
 
b/core/sis-utility/src/main/java/org/apache/sis/internal/util/StandardDateFormat.java
index 75fd103..9f9cc38 100644
--- 
a/core/sis-utility/src/main/java/org/apache/sis/internal/util/StandardDateFormat.java
+++ 
b/core/sis-utility/src/main/java/org/apache/sis/internal/util/StandardDateFormat.java
@@ -27,12 +27,14 @@ import java.text.ParsePosition;
 import java.text.ParseException;
 import java.time.DateTimeException;
 import java.time.Instant;
+import java.time.LocalTime;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.OffsetDateTime;
 import java.time.OffsetTime;
 import java.time.ZoneId;
 import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
 import java.time.temporal.Temporal;
 import java.time.temporal.ChronoField;
 import java.time.temporal.TemporalQuery;
@@ -50,9 +52,9 @@ import org.apache.sis.util.CharSequences;
  * the time is optional. For this class, "Standard" is interpreted as "close 
to ISO 19162 requirements",
  * which is not necessarily identical to other ISO standards.
  *
- * External users should use nothing else than the parsing and formatting 
methods.
+ * <p>External users should use nothing else than the parsing and formatting 
methods.
  * The methods for configuring the {@code DateFormat} instances may or may not 
work
- * depending on the branch.
+ * depending on the branch.</p>
  *
  * <p>The main usage for this class is Well Known Text (WKT) parsing and 
formatting.
  * ISO 19162 uses ISO 8601:2004 for the dates. Any precision is allowed: the 
date could have only the year,
@@ -312,6 +314,39 @@ replace:    if (Character.isWhitespace(c)) {
     }
 
     /**
+     * Returns {@code true} if objects of the given class have day, month and 
hour fields.
+     * This method is defined here for having a single class where to 
concentrate such heuristic rules.
+     * Note that {@link Instant} does not have date fields.
+     *
+     * @param  date  class of object to test (may be {@code null}).
+     * @return whether the given class is {@link LocalDate} or one of the 
classes with date + time.
+     *         This list may be expanded in future versions.
+     */
+    public static boolean hasDateFields(final Class<?> date) {
+        return date == LocalDate.class
+            || date == LocalDateTime.class
+            || date == OffsetDateTime.class
+            || date == ZonedDateTime.class;
+    }
+
+    /**
+     * Returns {@code true} if objects of the given class have time fields.
+     * This method is defined here for having a single class where to 
concentrate such heuristic rules.
+     * Note that {@link Instant} does not have hour fields.
+     *
+     * @param  date  class of object to test (may be {@code null}).
+     * @return whether the given class is {@link LocalTime}, {@link 
OffsetTime} or one of the classes with date + time.
+     *         This list may be expanded in future versions.
+     */
+    public static boolean hasTimeFields(final Class<?> date) {
+        return date == LocalTime.class
+            || date == OffsetTime.class
+            || date == LocalDateTime.class
+            || date == OffsetDateTime.class
+            || date == ZonedDateTime.class;
+    }
+
+    /**
      * The {@code java.time} parser and formatter. This is usually the {@link 
#FORMAT} instance
      * unless a different locale or timezone has been specified.
      */
diff --git a/core/sis-utility/src/main/java/org/apache/sis/measure/Range.java 
b/core/sis-utility/src/main/java/org/apache/sis/measure/Range.java
index 14d22f1..5cb6f5c 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/measure/Range.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/measure/Range.java
@@ -721,7 +721,7 @@ public class Range<E extends Comparable<? super E>> 
implements CheckedContainer<
     }
 
     /**
-     * Formats this range using the provider formatter. This method is invoked 
when a
+     * Formats this range using the provided formatter. This method is invoked 
when a
      * {@code Range} object is formatted using the {@code "%s"} conversion 
specifier of
      * {@link Formatter}. Users don't need to invoke this method explicitly.
      *
diff --git 
a/core/sis-utility/src/main/java/org/apache/sis/measure/RangeFormat.java 
b/core/sis-utility/src/main/java/org/apache/sis/measure/RangeFormat.java
index 50e2796..cb21a87 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/measure/RangeFormat.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/measure/RangeFormat.java
@@ -31,6 +31,10 @@ import java.text.AttributedCharacterIterator;
 import java.text.FieldPosition;
 import java.text.ParseException;
 import java.text.ParsePosition;
+import java.time.format.FormatStyle;
+import java.time.format.DateTimeFormatterBuilder;
+import java.time.temporal.Temporal;
+import java.time.Instant;
 import java.security.AccessController;
 import javax.measure.Unit;
 import org.apache.sis.util.Numbers;
@@ -39,6 +43,7 @@ import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.util.UnconvertibleObjectException;
 import org.apache.sis.internal.util.LocalizedParseException;
+import org.apache.sis.internal.util.StandardDateFormat;
 import org.apache.sis.internal.util.FinalFieldSetter;
 import org.apache.sis.internal.util.Numerics;
 
@@ -94,7 +99,7 @@ import org.apache.sis.internal.util.Numerics;
  * </ul>
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 1.0
+ * @version 1.1
  *
  * @see Range#toString()
  * @see <a href="https://en.wikipedia.org/wiki/ISO_31-11";>Wikipedia: ISO 
31-11</a>
@@ -358,9 +363,14 @@ public class RangeFormat extends Format implements 
Localized {
         } else if (Number.class.isAssignableFrom(elementType)) {
             elementFormat = NumberFormat.getNumberInstance(locale);
             unitFormat    = new UnitFormat(locale);
-        } else if (Date.class.isAssignableFrom(elementType)) {
+        } else if (Date.class.isAssignableFrom(elementType) || elementType == 
Instant.class) {
             elementFormat = DateFormat.getDateTimeInstance(DateFormat.SHORT, 
DateFormat.SHORT, locale);
             unitFormat    = null;
+        } else if (Temporal.class.isAssignableFrom(elementType)) {
+            final FormatStyle dateStyle = 
StandardDateFormat.hasDateFields(elementType) ? FormatStyle.SHORT : null;
+            final FormatStyle timeStyle = 
StandardDateFormat.hasTimeFields(elementType) ? FormatStyle.SHORT : null;
+            elementFormat = new 
DateTimeFormatterBuilder().appendLocalized(dateStyle, 
timeStyle).toFormatter(locale).toFormat();
+            unitFormat    = null;
         } else {
             throw new 
IllegalArgumentException(Errors.format(Errors.Keys.UnsupportedType_1, 
elementType));
         }
@@ -528,7 +538,8 @@ public class RangeFormat extends Format implements 
Localized {
 
     /**
      * Casts the given object to a {@code Range}, or throws an {@code 
IllegalArgumentException}
-     * if the given object is not a {@code Range} instance.
+     * if the given object is not a {@code Range} instance. This is used for 
validating argument
+     * of {@link Object} type in formatting methods.
      */
     private static Range<?> cast(final Object range) throws 
IllegalArgumentException {
         if (range instanceof Range<?>) {
@@ -610,8 +621,8 @@ public class RangeFormat extends Format implements 
Localized {
         for (; field <= UNIT_FIELD; field++) {
             final Object value;
             switch (field) {
-                case MIN_VALUE_FIELD: value = minValue; break;
-                case MAX_VALUE_FIELD: value = maxValue; break;
+                case MIN_VALUE_FIELD: value = toFormattable(minValue); break;
+                case MAX_VALUE_FIELD: value = toFormattable(maxValue); break;
                 case UNIT_FIELD:      value = range.unit(); break;
                 default: throw new AssertionError(field);
             }
@@ -1016,7 +1027,8 @@ public class RangeFormat extends Format implements 
Localized {
     }
 
     /**
-     * Converts the given value to the a {@link #elementType} type.
+     * Converts the given value to an instance of the {@link #elementType} 
type.
+     * This method is partially the converse of {@link #toFormattable(Object)}.
      */
     @SuppressWarnings("unchecked")
     private Object convert(final Object value) throws 
UnconvertibleObjectException {
@@ -1026,11 +1038,25 @@ public class RangeFormat extends Format implements 
Localized {
         if (value instanceof Number && 
Number.class.isAssignableFrom(elementType)) {
             return Numbers.cast((Number) value, (Class<? extends Number>) 
elementType);
         }
+        if (value instanceof Date && elementType == Instant.class) {
+            return ((Date) value).toInstant();
+        }
         throw new UnconvertibleObjectException(Errors.format(
                 Errors.Keys.IllegalClass_2, elementType, value.getClass()));
     }
 
     /**
+     * Converts the given object to a type that {@code format(…)} method can 
process.
+     * This method is partially the converse of {@link #convert(Object)}.
+     */
+    private Object toFormattable(final Object value) {
+        if (value instanceof Instant && elementType == Instant.class) {
+            return Date.from((Instant) value);
+        }
+        return value;
+    }
+
+    /**
      * Returns a "nil" value. This is used for creating empty ranges.
      */
     private Object valueOfNil() {
diff --git 
a/core/sis-utility/src/test/java/org/apache/sis/measure/RangeFormatTest.java 
b/core/sis-utility/src/test/java/org/apache/sis/measure/RangeFormatTest.java
index 0226cf2..ba197fa 100644
--- a/core/sis-utility/src/test/java/org/apache/sis/measure/RangeFormatTest.java
+++ b/core/sis-utility/src/test/java/org/apache/sis/measure/RangeFormatTest.java
@@ -19,6 +19,9 @@ package org.apache.sis.measure;
 import java.util.Date;
 import java.util.Locale;
 import java.util.TimeZone;
+import java.time.Instant;
+import java.time.LocalTime;
+import java.time.LocalDate;
 import java.text.DateFormat;
 import java.text.FieldPosition;
 import java.text.ParsePosition;
@@ -39,7 +42,7 @@ import static 
org.apache.sis.internal.util.StandardDateFormat.UTC;
  * Tests parsing and formatting done by the {@link RangeFormat} class.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.8
+ * @version 1.1
  * @since   0.3
  * @module
  */
@@ -302,6 +305,45 @@ public final strictfp class RangeFormatTest extends 
TestCase {
     }
 
     /**
+     * Tests formatting a range of {@link LocalDate} objects.
+     */
+    @Test
+    public void testFormatLocalDate() {
+        format = new RangeFormat(Locale.CANADA_FRENCH, LocalDate.class);
+        final Range<LocalDate> range = new Range<>(LocalDate.class,
+                LocalDate.parse("2019-12-23"), true,
+                LocalDate.parse("2020-05-31"), true);
+
+        assertEquals("[2019-12-23 … 2020-05-31]", format.format(range));
+    }
+
+    /**
+     * Tests formatting a range of {@link LocalTime} objects.
+     */
+    @Test
+    public void testFormatLocalTime() {
+        format = new RangeFormat(Locale.FRANCE, LocalTime.class);
+        final Range<LocalTime> range = new Range<>(LocalTime.class,
+                LocalTime.parse("06:00:00"), true,
+                LocalTime.parse("18:00:00"), true);
+
+        assertEquals("[06:00 … 18:00]", format.format(range));
+    }
+
+    /**
+     * Tests formatting a range of {@link Instant} objects.
+     */
+    @Test
+    public void testFormatInstant() {
+        format = new RangeFormat(Locale.FRANCE, Instant.class);
+        final Range<Instant> range = new Range<>(Instant.class,
+                Instant.parse("2019-12-23T06:00:00Z"), true,
+                Instant.parse("2020-05-31T18:00:00Z"), true);
+
+        assertEquals("[23/12/2019 07:00 … 31/05/2020 20:00]", 
format.format(range));
+    }
+
+    /**
      * Tests the {@link RangeFormat#formatToCharacterIterator(Object)} method 
with dates.
      */
     @Test
diff --git 
a/core/sis-utility/src/test/java/org/apache/sis/measure/RangeTest.java 
b/core/sis-utility/src/test/java/org/apache/sis/measure/RangeTest.java
index e00a646..d0732e3 100644
--- a/core/sis-utility/src/test/java/org/apache/sis/measure/RangeTest.java
+++ b/core/sis-utility/src/test/java/org/apache/sis/measure/RangeTest.java
@@ -17,6 +17,7 @@
 package org.apache.sis.measure;
 
 import java.util.Locale;
+import java.time.Instant;
 import org.apache.sis.test.TestCase;
 import org.junit.Test;
 
@@ -28,7 +29,8 @@ import static org.apache.sis.test.Assert.*;
  * Tests the {@link Range} class.
  *
  * @author  Joe White
- * @version 0.3
+ * @author  Martin Desruisseaux (Geomatys)
+ * @version 1.1
  * @since   0.3
  * @module
  */
@@ -323,6 +325,18 @@ public final strictfp class RangeTest extends TestCase {
     }
 
     /**
+     * Tests the {@link Range#formatTo(Formatter, int, int, int)} method with 
a range of instants.
+     */
+    @Test
+    public void testFormatInstantTo() {
+        final Range<Instant> range = new Range<>(Instant.class,
+                Instant.parse("2019-12-23T06:00:00Z"), true,
+                Instant.parse("2020-05-31T18:00:00Z"), true);
+
+        assertEquals("[23/12/2019 07:00 … 31/05/2020 20:00]", 
String.format(Locale.FRANCE, "%s", range));
+    }
+
+    /**
      * Tests the {@link Range#equals(Object)} method.
      */
     @Test

Reply via email to