Commit 969afd98 authored by Evan Ward's avatar Evan Ward
Browse files

Fix #881 rounded date to string w/o UTC offset

Previously there was no combination of methods that would generate a
rounded AbsoluteDate without UTC offset, which was the behavior of
AbsoluteDate.toString() in Orekit 10. Added methods and tests.
parent 6550a89f
Pipeline #1649 passed with stages
in 26 minutes and 28 seconds
...@@ -21,6 +21,11 @@ ...@@ -21,6 +21,11 @@
</properties> </properties>
<body> <body>
<release version="11.1" date="TBD" description="TBD"> <release version="11.1" date="TBD" description="TBD">
<action dev="evan" type="add" issue="881">
Add AbsoluteDate.toStringWithoutUtcOffset(TimeScale, int) and
DateTimeComponents.toStringWithoutUtcOffset(int, int) to emulate
AbsoluteDate.toString() from Orekit 10.
</action>
<action dev="evan" type="fix" issue="880"> <action dev="evan" type="fix" issue="880">
Fix UTC offset in DateTimeComponents.toString(int, int) Fix UTC offset in DateTimeComponents.toString(int, int)
</action> </action>
......
...@@ -1455,4 +1455,31 @@ public class AbsoluteDate ...@@ -1455,4 +1455,31 @@ public class AbsoluteDate
return this.getComponents(utc).toStringRfc3339(); return this.getComponents(utc).toStringRfc3339();
} }
/**
* Return a string representation of this date-time, rounded to the given precision.
*
* <p>The format used is ISO8601 without the UTC offset.</p>
*
* <p>Calling {@code toStringWithoutUtcOffset(DataContext.getDefault().getTimeScales().getUTC(),
* 3)} will emulate the behavior of {@link #toString()} in Orekit 10 and earlier. Note
* this method is more accurate as it correctly handles rounding during leap seconds.
*
* @param timeScale to use to compute components.
* @param fractionDigits the number of digits to include after the decimal point in
* the string representation of the seconds. The date and time
* is first rounded as necessary. {@code fractionDigits} must be
* greater than or equal to {@code 0}.
* @return string representation of this date, time, and UTC offset
* @see #toString(TimeScale)
* @see #toStringRfc3339(TimeScale)
* @see DateTimeComponents#toString(int, int)
* @see DateTimeComponents#toStringWithoutUtcOffset(int, int)
* @since 11.1
*/
public String toStringWithoutUtcOffset(final TimeScale timeScale,
final int fractionDigits) {
return this.getComponents(timeScale)
.toStringWithoutUtcOffset(timeScale.minuteDuration(this), fractionDigits);
}
} }
...@@ -243,6 +243,7 @@ public class DateTimeComponents implements Serializable, Comparable<DateTimeComp ...@@ -243,6 +243,7 @@ public class DateTimeComponents implements Serializable, Comparable<DateTimeComp
* format used is ISO6801, except without the offset from UTC. * format used is ISO6801, except without the offset from UTC.
* *
* @return a string representation of the date-time. * @return a string representation of the date-time.
* @see #toStringWithoutUtcOffset(int, int)
* @see #toString(int, int) * @see #toString(int, int)
* @see #toStringRfc3339() * @see #toStringRfc3339()
*/ */
...@@ -282,9 +283,34 @@ public class DateTimeComponents implements Serializable, Comparable<DateTimeComp ...@@ -282,9 +283,34 @@ public class DateTimeComponents implements Serializable, Comparable<DateTimeComp
* @return string representation of this date, time, and UTC offset * @return string representation of this date, time, and UTC offset
* @see #toStringRfc3339() * @see #toStringRfc3339()
* @see #toStringWithoutUtcOffset() * @see #toStringWithoutUtcOffset()
* @see #toStringWithoutUtcOffset(int, int)
* @since 11.0 * @since 11.0
*/ */
public String toString(final int minuteDuration, final int fractionDigits) { public String toString(final int minuteDuration, final int fractionDigits) {
return toStringWithoutUtcOffset(minuteDuration, fractionDigits) +
time.formatUtcOffset();
}
/**
* Return a string representation of this date-time, rounded to the given precision.
*
* <p>The format used is ISO8601 without the UTC offset.</p>
*
* @param minuteDuration 59, 60, 61, or 62 seconds depending on the date being close
* to a leap second introduction and the magnitude of the leap
* second.
* @param fractionDigits the number of digits to include after the decimal point in
* the string representation of the seconds. The date and time
* is first rounded as necessary. {@code fractionDigits} must
* be greater than or equal to {@code 0}.
* @return string representation of this date, time, and UTC offset
* @see #toStringRfc3339()
* @see #toStringWithoutUtcOffset()
* @see #toString(int, int)
* @since 11.1
*/
public String toStringWithoutUtcOffset(final int minuteDuration,
final int fractionDigits) {
final DecimalFormat secondsFormat = final DecimalFormat secondsFormat =
new DecimalFormat("00", new DecimalFormatSymbols(Locale.US)); new DecimalFormat("00", new DecimalFormatSymbols(Locale.US));
secondsFormat.setMaximumFractionDigits(fractionDigits); secondsFormat.setMaximumFractionDigits(fractionDigits);
...@@ -309,11 +335,10 @@ public class DateTimeComponents implements Serializable, Comparable<DateTimeComp ...@@ -309,11 +335,10 @@ public class DateTimeComponents implements Serializable, Comparable<DateTimeComp
} }
} }
roundedDate = new DateComponents(j2000); roundedDate = new DateComponents(j2000);
roundedTime = new TimeComponents(hour, minute, second, time.getMinutesFromUTC()); roundedTime = new TimeComponents(hour, minute, second);
} }
return roundedDate.toString() + 'T' + return roundedDate.toString() + 'T' +
roundedTime.toStringWithoutUtcOffset(secondsFormat) + roundedTime.toStringWithoutUtcOffset(secondsFormat);
roundedTime.formatUtcOffset();
} }
/** /**
......
...@@ -1292,6 +1292,57 @@ public class AbsoluteDateTest { ...@@ -1292,6 +1292,57 @@ public class AbsoluteDateTest {
MatcherAssert.assertThat(d.getComponents(utc).toString(), CoreMatchers.is(s + "+00:00")); MatcherAssert.assertThat(d.getComponents(utc).toString(), CoreMatchers.is(s + "+00:00"));
} }
@Test
public void testToStringWithoutUtcOffset() {
// setup
AbsoluteDate date = new AbsoluteDate(2009, 1, 1, utc);
double one = FastMath.nextDown(1.0);
double zeroUlp = FastMath.nextUp(0.0);
double oneUlp = FastMath.ulp(1.0);
//double sixty = FastMath.nextDown(60.0);
double sixtyUlp = FastMath.ulp(60.0);
// action
// test midnight
checkToStringNoOffset(date, "2009-01-01T00:00:00.000");
checkToStringNoOffset(date.shiftedBy(1), "2009-01-01T00:00:01.000");
// test digits and rounding
checkToStringNoOffset(date.shiftedBy(12.3456789123456789), "2009-01-01T00:00:12.346");
checkToStringNoOffset(date.shiftedBy(0.0123456789123456789), "2009-01-01T00:00:00.012");
// test min and max values
checkToStringNoOffset(date.shiftedBy(zeroUlp), "2009-01-01T00:00:00.000");
// Orekit 10.1 rounds up
checkToStringNoOffset(date.shiftedBy(59.0).shiftedBy(one), "2009-01-01T00:01:00.000");
// Orekit 10.1 rounds up
checkToStringNoOffset(date.shiftedBy(86399).shiftedBy(one), "2009-01-02T00:00:00.000");
checkToStringNoOffset(date.shiftedBy(oneUlp), "2009-01-01T00:00:00.000");
checkToStringNoOffset(date.shiftedBy(one), "2009-01-01T00:00:01.000");
checkToStringNoOffset(date.shiftedBy(-zeroUlp), "2009-01-01T00:00:00.000");
// test leap
// Orekit 10.1 throw OIAE, 10.2 rounds up
checkToStringNoOffset(date.shiftedBy(-oneUlp), "2009-01-01T00:00:00.000");
// Orekit 10.1 rounds up
checkToStringNoOffset(date.shiftedBy(-1).shiftedBy(one), "2009-01-01T00:00:00.000");
checkToStringNoOffset(date.shiftedBy(-0.5), "2008-12-31T23:59:60.500");
checkToStringNoOffset(date.shiftedBy(-1).shiftedBy(zeroUlp), "2008-12-31T23:59:60.000");
checkToStringNoOffset(date.shiftedBy(-1), "2008-12-31T23:59:60.000");
checkToStringNoOffset(date.shiftedBy(-1).shiftedBy(-zeroUlp), "2008-12-31T23:59:60.000");
checkToStringNoOffset(date.shiftedBy(-1).shiftedBy(-oneUlp), "2008-12-31T23:59:60.000");
checkToStringNoOffset(date.shiftedBy(-2), "2008-12-31T23:59:59.000");
// Orekit 10.1 rounds up
checkToStringNoOffset(date.shiftedBy(-1).shiftedBy(-sixtyUlp), "2008-12-31T23:59:60.000");
checkToStringNoOffset(date.shiftedBy(-61).shiftedBy(zeroUlp), "2008-12-31T23:59:00.000");
checkToStringNoOffset(date.shiftedBy(-61).shiftedBy(oneUlp), "2008-12-31T23:59:00.000");
}
private void checkToStringNoOffset(final AbsoluteDate d, final String s) {
MatcherAssert.assertThat(d.toStringWithoutUtcOffset(utc, 3), CoreMatchers.is(s));
MatcherAssert.assertThat(
d.getComponents(utc).toStringWithoutUtcOffset(utc.minuteDuration(d), 3),
CoreMatchers.is(s));
}
/** /**
* Check {@link AbsoluteDate#toString()} when UTC throws an exception. This ~is~ was * Check {@link AbsoluteDate#toString()} when UTC throws an exception. This ~is~ was
* the most common issue new and old users face. * the most common issue new and old users face.
......
...@@ -205,4 +205,13 @@ public class DateTimeComponentsTest { ...@@ -205,4 +205,13 @@ public class DateTimeComponentsTest {
MatcherAssert.assertThat(dtc.toString(60, 14), CoreMatchers.is("2000-12-31T23:59:59.90000000000000-01:32")); MatcherAssert.assertThat(dtc.toString(60, 14), CoreMatchers.is("2000-12-31T23:59:59.90000000000000-01:32"));
} }
@Test
public void testToStringWithoutUtcOffsetRoundingUtcOffset() {
DateTimeComponents dtc =
new DateTimeComponents(new DateComponents(2000, 12, 31), new TimeComponents(23, 59, 59.9, -92));
MatcherAssert.assertThat(dtc.toStringWithoutUtcOffset(60, 3), CoreMatchers.is("2000-12-31T23:59:59.900"));
MatcherAssert.assertThat(dtc.toStringWithoutUtcOffset(60, 0), CoreMatchers.is("2001-01-01T00:00:00"));
MatcherAssert.assertThat(dtc.toStringWithoutUtcOffset(60, 14), CoreMatchers.is("2000-12-31T23:59:59.90000000000000"));
}
} }
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment