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 <[email protected]>
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.