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: Take in account the case where the temporal origin of a dataset has fractional seconds.
Date Sat, 02 Mar 2019 13:32:21 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 0218c71  Take in account the case where the temporal origin of a dataset has fractional
seconds.
0218c71 is described below

commit 0218c7138eab2767f5479f5d108fba6ea010e075
Author: Martin Desruisseaux <martin.desruisseaux@geomatys.com>
AuthorDate: Sat Mar 2 14:19:59 2019 +0100

    Take in account the case where the temporal origin of a dataset has fractional seconds.
---
 .../sis/referencing/crs/DefaultTemporalCRS.java    | 44 +++++++++++++++++++--
 .../referencing/crs/DefaultTemporalCRSTest.java    | 46 +++++++++++++++++++---
 .../sis/internal/util/StandardDateFormat.java      |  6 +--
 3 files changed, 84 insertions(+), 12 deletions(-)

diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultTemporalCRS.java
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultTemporalCRS.java
index 0a041d4..03072d9 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultTemporalCRS.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultTemporalCRS.java
@@ -26,6 +26,7 @@ import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
 import javax.measure.quantity.Time;
 import javax.measure.UnitConverter;
+import javax.measure.Unit;
 import org.opengis.referencing.cs.CoordinateSystem;
 import org.opengis.referencing.cs.TimeCS;
 import org.opengis.referencing.crs.TemporalCRS;
@@ -36,6 +37,7 @@ import org.apache.sis.internal.metadata.MetadataUtilities;
 import org.apache.sis.internal.metadata.WKTKeywords;
 import org.apache.sis.io.wkt.Formatter;
 import org.apache.sis.measure.Units;
+import org.apache.sis.math.Fraction;
 
 import static org.apache.sis.util.ArgumentChecks.ensureNonNull;
 import static org.apache.sis.internal.util.StandardDateFormat.NANOS_PER_SECOND;
@@ -218,8 +220,19 @@ public class DefaultTemporalCRS extends AbstractCRS implements TemporalCRS
{
      * Initialize the fields required for {@link #toInstant(double)} and {@link #toValue(Instant)}
operations.
      */
     private void initializeConverter() {
-        origin    = datum.getOrigin().getTime() / MILLIS_PER_SECOND;
-        toSeconds = super.getCoordinateSystem().getAxis(0).getUnit().asType(Time.class).getConverterTo(Units.SECOND);
+        toSeconds = getUnit().getConverterTo(Units.SECOND);
+        long t = datum.getOrigin().getTime();
+        origin = t / MILLIS_PER_SECOND;
+        t %= MILLIS_PER_SECOND;
+        if (t != 0) {
+            /*
+             * The origin is usually an integer amount of days or hours. It rarely has a
fractional amount of seconds.
+             * If it happens anyway, put the fractional amount of seconds in the converter
instead than adding another
+             * field in this class for such very rare situation. Accuracy should be okay
since the offset is small.
+             */
+            UnitConverter c = Units.converter(null, new Fraction((int) t, MILLIS_PER_SECOND).simplify());
+            toSeconds = c.concatenate(toSeconds);
+        }
     }
 
     /**
@@ -261,6 +274,27 @@ public class DefaultTemporalCRS extends AbstractCRS implements TemporalCRS
{
     }
 
     /**
+     * Returns the unit of measurement of temporal measurement in the coordinate reference
system.
+     * This is a convenience method for {@link org.opengis.referencing.cs.CoordinateSystemAxis#getUnit()}
+     * on the unique axis of this coordinate reference system. The unit of measurement returned
by this method
+     * is the unit of the value expected in argument by {@link #toInstant(double)} and {@link
#toDate(double)},
+     * and the unit of the value returned by {@code toValue(…)} methods.
+     *
+     * <div class="note"><b>Implementation note:</b>
+     * this method is declared final and does not invoke overridden {@link #getCoordinateSystem()}
method
+     * because this {@code getUnit()} method is invoked indirectly by constructors. Another
reason is that
+     * the overriding point is the {@code CoordinateSystemAxis.getUnit()} method and we want
to avoid
+     * introducing another overriding point that could be inconsistent with above method.</div>
+     *
+     * @return the temporal unit of measurement of coordinates in this CRS.
+     *
+     * @since 1.0
+     */
+    public final Unit<Time> getUnit() {
+        return super.getCoordinateSystem().getAxis(0).getUnit().asType(Time.class);
+    }
+
+    /**
      * {@inheritDoc}
      *
      * @return {@inheritDoc}
@@ -283,7 +317,7 @@ public class DefaultTemporalCRS extends AbstractCRS implements TemporalCRS
{
      * If the given value {@linkplain Double#isNaN is NaN} or infinite, then this method
returns {@code null}.
      * This method is the converse of {@link #toValue(Instant)}.
      *
-     * @param  value  a value in this axis unit.
+     * @param  value  a value in this axis. Unit of measurement is given by {@link #getUnit()}.
      * @return the value as an instant, or {@code null} if the given value is NaN or infinite.
      *
      * @since 1.0
@@ -307,7 +341,7 @@ public class DefaultTemporalCRS extends AbstractCRS implements TemporalCRS
{
      * <p>This method is provided for interoperability with legacy {@code java.util.Date}
object.
      * New code should use {@link #toInstant(double)} instead.</p>
      *
-     * @param  value  a value in this axis unit.
+     * @param  value  a value in this axis unit. Unit of measurement is given by {@link #getUnit()}.
      * @return the value as a {@linkplain Date date}, or {@code null} if the given value
is NaN or infinite.
      */
     public Date toDate(double value) {
@@ -330,6 +364,7 @@ public class DefaultTemporalCRS extends AbstractCRS implements TemporalCRS
{
      *
      * @param  time  the value as an instant, or {@code null}.
      * @return the value in this axis unit, or {@link Double#NaN} if the given instant is
{@code null}.
+     *         Unit of measurement is given by {@link #getUnit()}.
      *
      * @since 1.0
      */
@@ -353,6 +388,7 @@ public class DefaultTemporalCRS extends AbstractCRS implements TemporalCRS
{
      *
      * @param  time  the value as a {@linkplain Date date}, or {@code null}.
      * @return the value in this axis unit, or {@link Double#NaN} if the given time is {@code
null}.
+     *         Unit of measurement is given by {@link #getUnit()}.
      */
     public double toValue(final Date time) {
         if (time != null) {
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/DefaultTemporalCRSTest.java
b/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/DefaultTemporalCRSTest.java
index 5729528..9b07d48 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/DefaultTemporalCRSTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/DefaultTemporalCRSTest.java
@@ -18,11 +18,16 @@ package org.apache.sis.referencing.crs;
 
 import java.time.Instant;
 import java.util.Date;
+import java.util.Collections;
+import org.apache.sis.referencing.datum.DefaultTemporalDatum;
+import org.apache.sis.referencing.cs.HardCodedCS;
 import org.apache.sis.io.wkt.Convention;
 import org.apache.sis.test.TestCase;
 import org.junit.Test;
 
 import static org.apache.sis.test.MetadataAssert.*;
+import static org.apache.sis.internal.util.StandardDateFormat.MILLISECONDS_PER_DAY;
+import static org.apache.sis.internal.util.StandardDateFormat.NANOS_PER_MILLISECOND;
 
 
 /**
@@ -82,12 +87,43 @@ public final strictfp class DefaultTemporalCRSTest extends TestCase {
      */
     @Test
     public void testDateConversion() {
-        final double  value   = 58543.25;                               // 3 march 2019.
-        final Date    date    = HardCodedCRS.TIME.toDate(value);
-        final Instant instant = HardCodedCRS.TIME.toInstant(value);
+        final DefaultTemporalCRS crs = HardCodedCRS.TIME;
+        final double  value   = 58543.25;                               // 2019-03-01T06:00:00Z
+        final Date    date    = crs.toDate(value);
+        final Instant instant = crs.toInstant(value);
         assertEquals("toInstant", Instant.ofEpochSecond(1551420000L), instant);
         assertEquals("toDate",    instant, date.toInstant());
-        assertEquals("toValue",   value, HardCodedCRS.TIME.toValue(instant), STRICT);
-        assertEquals("toValue",   value, HardCodedCRS.TIME.toValue(date), STRICT);
+        assertEquals("toValue",   value, crs.toValue(instant), STRICT);
+        assertEquals("toValue",   value, crs.toValue(date), STRICT);
+    }
+
+    /**
+     * Same as {@link #testDateConversion()} but with a nanosecond component.
+     * Fraction of seconds need to be handled in special way by current implementation.
+     */
+    @Test
+    public void testDateConversionWithNanos() {
+        final DefaultTemporalDatum datum = new DefaultTemporalDatum(
+                Collections.singletonMap(DefaultTemporalDatum.NAME_KEY, "For test"),
+                new Date(10000L * MILLISECONDS_PER_DAY + 12345));                       
// 1997-05-19T00:00:12.345Z
+        final DefaultTemporalCRS crs = new DefaultTemporalCRS(
+                Collections.singletonMap(DefaultTemporalCRS.NAME_KEY, datum.getName()),
+                datum, HardCodedCS.DAYS);
+        /*
+         * DefaultTemporalCRS.toSeconds converter should have a non-zero offset because of
the 0.345 seconds offset
+         * in temporal datum. Ask for a date two days after the origin and verify that the
12.345 part is missing.
+         */
+        final double ε = 1E-15;
+        assertEquals(2 - 12.345 / (60*60*24), crs.toValue(new Date(10002L * MILLISECONDS_PER_DAY)),
 ε);
+        assertEquals(2 - 12.345 / (60*60*24), crs.toValue(Instant.ofEpochSecond(10002L*(60*60*24))),
ε);
+        /*
+         * Add a millisecond component and test again.
+         */
+        final Instant t = Instant.ofEpochSecond(10002L*(60*60*24) + 15, 789 * NANOS_PER_MILLISECOND);
+        final double  v = 2 + (15.789 - 12.345) / (60*60*24);
+        assertEquals("toValue",   v,            crs.toValue(t), ε);
+        assertEquals("toValue",   v,            crs.toValue(Date.from(t)), ε);
+        assertEquals("toInstant", t,            crs.toInstant(v));
+        assertEquals("toDate",    Date.from(t), crs.toDate(v));
     }
 }
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 f347c34..86ed80d 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
@@ -232,17 +232,17 @@ replace:    if (Character.isWhitespace(c)) {
     /**
      * Number of milliseconds in one second.
      */
-    public static final long MILLIS_PER_SECOND = 1000;
+    public static final int MILLIS_PER_SECOND = 1000;
 
     /**
      * Number of nanoseconds in one millisecond.
      */
-    public static final long NANOS_PER_MILLISECOND = 1000000;
+    public static final int NANOS_PER_MILLISECOND = 1000000;
 
     /**
      * Number of nanoseconds in one second.
      */
-    public static final long NANOS_PER_SECOND = 1000000000;
+    public static final int NANOS_PER_SECOND = 1000000000;
 
     /**
      * Converts the given legacy {@code Date} object into a {@code java.time} implementation
in given timezone.


Mime
View raw message