Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,14 @@ public static String toDecimal(long seconds, int nanoseconds)
*/
public static BigDecimal toBigDecimal(long seconds, int nanoseconds)
{
// [modules-java8#359] For negative seconds with positive nanos (times before epoch),
// we need to compute the proper decimal value: seconds + (nanos / 1_000_000_000)
// Example: Instant{epochSecond=-1, nano=999000000} represents -0.001 seconds
if (seconds < 0 && nanoseconds > 0) {
return BigDecimal.valueOf(seconds)
.add(BigDecimal.valueOf(nanoseconds).scaleByPowerOfTen(-9));
}

if (nanoseconds == 0L) {
// 14-Mar-2015, tatu: Let's retain one zero to avoid interpretation
// as integral number
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -480,8 +480,9 @@ protected T _fromDecimal(DeserializationContext context, BigDecimal value)
{
FromDecimalArguments args =
DecimalUtils.extractSecondsAndNanos(value, (s, ns) -> new FromDecimalArguments(s, ns, getZone(context)),
// [modules-java8#337] since 2.19, only Instant needs negative adjustment
true);
// [modules-java8#359] since 2.21, Instant.ofEpochSecond() correctly handles
// negative nanoseconds, so no adjustment needed
false);
return fromNanoseconds.apply(args);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
package com.fasterxml.jackson.datatype.jsr310.tofix;
package com.fasterxml.jackson.datatype.jsr310.deser;

import java.time.Instant;

import org.junit.jupiter.api.Test;

import com.fasterxml.jackson.databind.ObjectReader;
import com.fasterxml.jackson.datatype.jsr310.ModuleTestBase;
import com.fasterxml.jackson.datatype.jsr310.testutil.failure.JacksonTestFailureExpected;

import static org.junit.jupiter.api.Assertions.assertEquals;

Expand All @@ -18,7 +17,6 @@ public class InstantDeserializerNegative359Test
{
private final ObjectReader READER = newMapper().readerFor(Instant.class);

@JacksonTestFailureExpected
@Test
public void testDeserializationAsFloat04()
throws Exception
Expand Down
3 changes: 3 additions & 0 deletions release-notes/CREDITS-2.x
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,9 @@ Kevin Mahon (@Strongbeard)
* Fixed #291: `InstantDeserializer` fails to parse negative numeric timestamp strings
for pre-1970 values
(2.18.4)
* Reported #359: `InstantDeserializer` deserializes the nanosecond portion of fractional
negative timestamps incorrectly
(2.21.0)

Joey Muia (@jmuia)
* Reported #337: Negative `Duration` does not round-trip properly with
Expand Down
5 changes: 5 additions & 0 deletions release-notes/VERSION-2.x
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ Modules:

2.21.0 (not yet released)

#359: `InstantDeserializer` deserializes the nanosecond portion of fractional
negative timestamps incorrectly
(reported by Kevin M)
(fix by @cowtowncoder, w/ Claude code)

No changes since 2.20

2.20.1 (30-Oct-2025)
Expand Down
Loading