You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sis.apache.org by de...@apache.org on 2020/10/22 14:14:09 UTC

[sis] 01/03: Accept parsing timezone name (e.g. "UTC") in addition of timezone offsets. Add links in javadoc and fix the value shown in an error message.

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

commit 5f774e8869329061f51868403ea8be97102d65c4
Author: Martin Desruisseaux <ma...@geomatys.com>
AuthorDate: Wed Oct 21 12:36:48 2020 +0200

    Accept parsing timezone name (e.g. "UTC") in addition of timezone offsets.
    Add links in javadoc and fix the value shown in an error message.
---
 .../org/apache/sis/coverage/grid/GridExtent.java   |  4 ++-
 .../java/org/apache/sis/referencing/CommonCRS.java |  7 +++-
 .../sis/internal/util/StandardDateFormat.java      | 42 +++++++++++-----------
 .../sis/internal/util/StandardDateFormatTest.java  |  4 ++-
 4 files changed, 33 insertions(+), 24 deletions(-)

diff --git a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridExtent.java b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridExtent.java
index 7652d5b..40696b9 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridExtent.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/coverage/grid/GridExtent.java
@@ -824,8 +824,10 @@ public class GridExtent implements GridEnvelope, LenientComparable, Serializable
                 if (count < s) {
                     selected[count++] = i;
                 } else {
+                    long size = high - low;
+                    if (size != -1) size++;     // When interpreted as unsigned long, -1 is the maximal value.
                     throw new SubspaceNotSpecifiedException(Resources.format(Resources.Keys.NoNDimensionalSlice_3,
-                                    s, getAxisIdentification(i,i), Numerics.toUnsignedDouble(high - low)));
+                                s, getAxisIdentification(i,i), Numerics.toUnsignedDouble(size)));
                 }
             }
         }
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/CommonCRS.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/CommonCRS.java
index aee861f..e064e18 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/CommonCRS.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/CommonCRS.java
@@ -1528,7 +1528,10 @@ public enum CommonCRS {
      *
      * @author  Martin Desruisseaux (Geomatys)
      * @version 1.0
-     * @since   0.4
+     *
+     * @see Engineering#TIME
+     *
+     * @since 0.4
      * @module
      */
     public enum Temporal {
@@ -1862,6 +1865,8 @@ public enum CommonCRS {
          *     <td>{@link AxisDirection#FUTURE}</td></tr>
          *   <tr><th>Unit:</th> <td>{@link Units#SECOND}</td></tr>
          * </table></blockquote>
+         *
+         * @see Temporal
          */
         TIME(new DefaultEngineeringDatum(singletonMap(EngineeringDatum.NAME_KEY, "Time")));
 
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 f058773..284bab4 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
@@ -61,7 +61,7 @@ import org.apache.sis.util.CharSequences;
  * but nevertheless allows to specify a timezone.</p>
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 1.0
+ * @version 1.1
  * @since   0.6
  * @module
  */
@@ -87,6 +87,8 @@ public final class StandardDateFormat extends DateFormat {
      * The thread-safe instance to use for reading and formatting dates.
      * Only the year is mandatory, all other fields are optional at parsing time.
      * However all fields are written, including milliseconds at formatting time.
+     *
+     * @see #parseInstantUTC(CharSequence, int, int)
      */
     public static final DateTimeFormatter FORMAT = new DateTimeFormatterBuilder()
             .parseLenient()                    // For allowing fields with one digit instead of two.
@@ -98,16 +100,18 @@ public final class StandardDateFormat extends DateFormat {
             .optionalStart().appendLiteral(':').appendValue(ChronoField.SECOND_OF_MINUTE, 2)
                                                .appendFraction(ChronoField.MILLI_OF_SECOND, 3, 3, true)
             .optionalEnd().optionalEnd().optionalEnd()    // Move back to the optional block of HOUR_OF_DAY.
-//          .optionalStart().appendOffset("+H:MM:ss", "Z")
-            .optionalStart().appendOffsetId()               // TODO: replace by above line after we migrated to JDK10.
+            .optionalStart().appendZoneOrOffsetId()
             .toFormatter(Locale.ROOT);
 
     /**
      * The kinds of objects to get from calls to {@link #parseBest(CharSequence)}, in preference order.
      * The time is converted to UTC timezone if possible.
      *
-     * Tip: if we want to preserve the timezone instead than converting to UTC, we could try replacing
-     * {@code Instant::from} by {@code ZonedDateTime::from, OffsetDateTime::from}.
+     * <div class="note"><b>Tip:</b>
+     * if we want to preserve the timezone instead than converting to UTC, we could try replacing
+     * {@code Instant::from} by {@code ZonedDateTime::from, OffsetDateTime::from}.</div>
+     *
+     * @see #parseInstantUTC(CharSequence, int, int)
      */
     private static TemporalQuery<?>[] QUERIES = {
         Instant::from, LocalDateTime::from, LocalDate::from
@@ -175,18 +179,18 @@ public final class StandardDateFormat extends DateFormat {
      * @return sub-sequence of {@code text} from {@code lower} to {@code upper}, potentially modified.
      */
     static CharSequence toISO(CharSequence text, int lower, int upper) {
-        boolean isCopied = false;
         lower = CharSequences.skipLeadingWhitespaces (text, lower, upper);
         upper = CharSequences.skipTrailingWhitespaces(text, lower, upper);
+        StringBuilder buffer = null;
         int cp = 0;   // Non-whitespace character from previous iteration.
         for (int i = upper; i > lower;) {
             int c = Character.codePointBefore(text, i);
             int n = Character.charCount(c);
 replace:    if (Character.isWhitespace(c)) {
                 /*
-                 * Found whitespaces from 'i' inclusive (after computation below) to 'end' exclusive.
+                 * Found whitespaces from `i` inclusive (after computation below) to `end` exclusive.
                  * If no concurrent change, i > lower because text.charAt(lower) is not a whitespace.
-                 * Set 'c' to the character before whitespaces. 'cp' is the character after spaces.
+                 * Set `c` to the character before whitespaces. `cp` is the character after spaces.
                  */
                 int end = i;
                 i = CharSequences.skipTrailingWhitespaces(text, lower, i - n);
@@ -196,27 +200,23 @@ replace:    if (Character.isWhitespace(c)) {
                 if (Character.isDigit(cp) && Character.isDigit(c)) {
                     /*
                      * If the character before and after whitespaces are digits, maybe we have
-                     * the separation between date and timezone. Use ':' position as a check.
+                     * the separation between date and timezone. Use `:` position as a check.
                      */
                     isDateTimeSeparator = CharSequences.indexOf(text, ':', lower, upper) > end;
                     if (!isDateTimeSeparator) break replace;               // Skip replacement.
                 }
-                final StringBuilder b;
-                if (isCopied) {
-                    b = (StringBuilder) text;
-                } else {
-                    text = b = new StringBuilder(upper - lower).append(text, lower, upper);
-                    i       -= lower;
-                    end     -= lower;
-                    lower    = 0;
-                    isCopied = true;
+                if (buffer == null) {
+                    text  = buffer = new StringBuilder(upper - lower).append(text, lower, upper);
+                    i    -= lower;
+                    end  -= lower;
+                    lower = 0;
                 }
                 if (isDateTimeSeparator) {
-                    b.replace(i, end, "T");
+                    buffer.replace(i, end, "T");
                 } else {
-                    b.delete(i, end);
+                    buffer.delete(i, end);
                 }
-                upper = b.length();
+                upper = buffer.length();
             }
             i -= n;
             cp = c;
diff --git a/core/sis-utility/src/test/java/org/apache/sis/internal/util/StandardDateFormatTest.java b/core/sis-utility/src/test/java/org/apache/sis/internal/util/StandardDateFormatTest.java
index be4386d..58acc1e 100644
--- a/core/sis-utility/src/test/java/org/apache/sis/internal/util/StandardDateFormatTest.java
+++ b/core/sis-utility/src/test/java/org/apache/sis/internal/util/StandardDateFormatTest.java
@@ -34,7 +34,7 @@ import static org.junit.Assert.*;
  * Tests the {@link StandardDateFormat} class.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 1.0
+ * @version 1.1
  * @since   0.6
  * @module
  */
@@ -60,6 +60,7 @@ public final strictfp class StandardDateFormatTest extends TestCase {
         assertSame  ("2005-09-22",                toISO("2005-09-22"));
         assertEquals("2005-09-22T04:30:15",       toISO("  2005-09-22   04 : 30 : 15 "));
         assertEquals("1992-10-8T15:15:42.5-6:00", toISO("1992-10-8 15:15:42.5 -6:00"));
+        assertEquals("1960-01-01T00:00:00Z",      toISO("1960-01-01 00:00:00 Z"));
     }
 
     /**
@@ -129,6 +130,7 @@ public final strictfp class StandardDateFormatTest extends TestCase {
         assertEquals(Instant.ofEpochMilli(day + ((16*60 + 48)*60     )*1000),      StandardDateFormat.parseInstantUTC("2016-06-27T16:48"));
         assertEquals(Instant.ofEpochMilli(day + ((16*60 + 48)*60     )*1000),      StandardDateFormat.parseInstantUTC("2016-06-27 16:48"));
         assertEquals(Instant.ofEpochMilli(day),                                    StandardDateFormat.parseInstantUTC("2016-06-27"));
+        assertEquals(Instant.ofEpochMilli(day + 2000),                             StandardDateFormat.parseInstantUTC("2016-06-27 00:00:02 UTC"));
     }
 
     /**