diff --git a/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/InstantDeserializer.java b/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/InstantDeserializer.java index 7838200c..2aca24c6 100644 --- a/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/InstantDeserializer.java +++ b/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/InstantDeserializer.java @@ -61,12 +61,25 @@ public class InstantDeserializer = JavaTimeFeature.ALWAYS_ALLOW_STRINGIFIED_DATE_TIMESTAMPS.enabledByDefault(); /** - * Constants used to check if ISO 8601 time string is colonless. See [jackson-modules-java8#131] + * Constants used to check if ISO 8601 time string is colon-less. See [jackson-modules-java8#131] * * @since 2.13 */ protected static final Pattern ISO8601_COLONLESS_OFFSET_REGEX = Pattern.compile("[+-][0-9]{4}(?=\\[|$)"); + // @since 2.18.2 + private static OffsetDateTime decimalToOffsetDateTime(FromDecimalArguments args) { + // [jackson-modules-java8#308] Since 2.18.2 : Fix can't deserialize OffsetDateTime.MIN: Invalid value for EpochDay + if (args.integer == OffsetDateTime.MIN.toEpochSecond() && args.fraction == OffsetDateTime.MIN.getNano()) { + return OffsetDateTime.ofInstant(Instant.ofEpochSecond(OffsetDateTime.MIN.toEpochSecond(), OffsetDateTime.MIN.getNano()), OffsetDateTime.MIN.getOffset()); + } + // [jackson-modules-java8#308] Since 2.18.2 : For OffsetDateTime.MAX case + if (args.integer == OffsetDateTime.MAX.toEpochSecond() && args.fraction == OffsetDateTime.MAX.getNano()) { + return OffsetDateTime.ofInstant(Instant.ofEpochSecond(OffsetDateTime.MAX.toEpochSecond(), OffsetDateTime.MAX.getNano()), OffsetDateTime.MAX.getOffset()); + } + return OffsetDateTime.ofInstant(Instant.ofEpochSecond(args.integer, args.fraction), args.zoneId); + } + public static final InstantDeserializer INSTANT = new InstantDeserializer<>( Instant.class, DateTimeFormatter.ISO_INSTANT, Instant::from, @@ -82,7 +95,7 @@ public class InstantDeserializer OffsetDateTime.class, DateTimeFormatter.ISO_OFFSET_DATE_TIME, OffsetDateTime::from, a -> OffsetDateTime.ofInstant(Instant.ofEpochMilli(a.value), a.zoneId), - a -> OffsetDateTime.ofInstant(Instant.ofEpochSecond(a.integer, a.fraction), a.zoneId), + InstantDeserializer::decimalToOffsetDateTime, (d, z) -> (d.isEqual(OffsetDateTime.MIN) || d.isEqual(OffsetDateTime.MAX) ? d : d.withOffsetSameInstant(z.getRules().getOffset(d.toLocalDateTime()))), true, // yes, replace zero offset with Z DEFAULT_NORMALIZE_ZONE_ID, diff --git a/datetime/src/test/java/com/fasterxml/jackson/datatype/jsr310/deser/OffsetDateTimeDeserTest.java b/datetime/src/test/java/com/fasterxml/jackson/datatype/jsr310/deser/OffsetDateTimeDeserTest.java index c31922e8..e676230d 100644 --- a/datetime/src/test/java/com/fasterxml/jackson/datatype/jsr310/deser/OffsetDateTimeDeserTest.java +++ b/datetime/src/test/java/com/fasterxml/jackson/datatype/jsr310/deser/OffsetDateTimeDeserTest.java @@ -803,6 +803,22 @@ public void testDeserializationNoAdjustIfMAX() throws Exception assertEquals(date.getOffset(),actualValue.getOffset()); } + // [jackson-modules-java8#308] Can't deserialize OffsetDateTime.MIN: Invalid value for EpochDay + @Test + public void testOffsetDateTimeMinOrMax() throws Exception + { + _testOffsetDateTimeMinOrMax(OffsetDateTime.MIN); + _testOffsetDateTimeMinOrMax(OffsetDateTime.MAX); + } + + private void _testOffsetDateTimeMinOrMax(OffsetDateTime offsetDateTime) + throws Exception + { + String ser = MAPPER.writeValueAsString(offsetDateTime); + OffsetDateTime result = MAPPER.readValue(ser, OffsetDateTime.class); + assertIsEqual(offsetDateTime, result); + } + private static void assertIsEqual(OffsetDateTime expected, OffsetDateTime actual) { assertTrue("The value is not correct. Expected timezone-adjusted <" + expected + ">, actual <" + actual + ">.", diff --git a/release-notes/CREDITS-2.x b/release-notes/CREDITS-2.x index 54f33789..cb733c9e 100644 --- a/release-notes/CREDITS-2.x +++ b/release-notes/CREDITS-2.x @@ -203,3 +203,7 @@ Emanuel Trandafir (@etrandafir93) Ólafur Bragason (@olibraga) * Reported #319: `java.time.DateTimeException` serialization fails (2.18.1) + +Joo Hyuk Kim (@JooHyukKim) + * Fixed #308: Can't deserialize `OffsetDateTime.MIN`: Invalid value for EpochDay + (2.18.2) diff --git a/release-notes/VERSION-2.x b/release-notes/VERSION-2.x index 8d3d88f4..a57c63cd 100644 --- a/release-notes/VERSION-2.x +++ b/release-notes/VERSION-2.x @@ -8,6 +8,12 @@ Modules: === Releases === ------------------------------------------------------------------------ +2.18.2 (not yet released) + +#308: Can't deserialize `OffsetDateTime.MIN`: Invalid value for EpochDay + (reported by @sszuev) + (fix by Joo-Hyuk K) + 2.18.1 (28-Oct-2024) #319: `java.time.DateTimeException` serialization fails