Description
Version
2.15.4
- 2.19
and the current master
branch (commit c84b1a9 as of this post).
I have not tested anything earlier than what I plan to use.
Description
Please correct me if I am misguided on how negative fractional representations of timestamps should be parsed into java.time.Instant
objects. I expected -1.000000001
to deserialize to 1969-12-31T23:59:58.999999999Z
, but currently it deserializes to 1969-12-31T23:59:59.000000001Z
.
I assume when "splitting" the fraction into its whole seconds and nanoseconds portions, the negative sign should be distributed to both. In other words: -1.000000001 == -1 + -0.000000001
, but instead the behavior appears to be -1.000000001 == -1 + 0.000000001
.
Strangely, any scenario where the seconds portion is 0
deserializes as I expect it to. For example, -0.000000001
deserializes to 1969-12-31T23:59:59.999999999Z
. For some reason, the distribution of the negativity from seconds to nanoseconds is preserved here.
Adding the following unit test to datetime/src/test/java/tools/jackson/datatype/jsr310/deser/InstantDeserTest.java
should demonstrate the issue, where test 4 fails and test 5 succeeds:
@Test
public void testDeserializationAsFloat04() throws Exception {
Instant actual = READER.readValue("-1.000000001");
Instant expected = Instant.ofEpochSecond(-1L, -1L);
assertEquals(expected, actual);
}
@Test
public void testDeserializationAsFloat05() throws Exception {
Instant actual = READER.readValue("-0.000000001");
Instant expected = Instant.ofEpochSecond(0L, -1L);
assertEquals(expected, actual);
}
The following error is produced when executing the tests:
[ERROR] tools.jackson.datatype.jsr310.deser.InstantDeserTest.testDeserializationAsFloat04 -- Time elapsed: 0.128 s <<< FAILURE!
org.opentest4j.AssertionFailedError: expected: <1969-12-31T23:59:58.999999999Z> but was: <1969-12-31T23:59:59.000000001Z>
at [email protected]/org.junit.jupiter.api.AssertionFailureBuilder.build(AssertionFailureBuilder.java:151)
at [email protected]/org.junit.jupiter.api.AssertionFailureBuilder.buildAndThrow(AssertionFailureBuilder.java:132)
at [email protected]/org.junit.jupiter.api.AssertEquals.failNotEqual(AssertEquals.java:197)
at [email protected]/org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:182)
at [email protected]/org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:177)
at [email protected]/org.junit.jupiter.api.Assertions.assertEquals(Assertions.java:1145)
at tools.jackson.datatype.javatime/tools.jackson.datatype.jsr310.deser.InstantDeserTest.testDeserializationAsFloat04(InstantDeserTest.java:121)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
If my assumptions are correct, then the fix appears more complicated than just changing the negativeAdjustment
boolean passed to the call to DecimalUtils.extractSecondsAndNanos(BigDecimal, BiFunction, boolean)
within the _fromDecimal(DeserializationContext, BigDecimal)
function of InstantDeserializer
to false
since that causes unit test ZonedDateTimeSerTest#testSerializationAsTimestamp01NegativeSeconds
to fail.
Related Issues
I believe this is related to the implementation of the fix for issues #304, #69, and #132.