From 52b9ed0e3214940b6f32c1f6eccfe8a82b3ef03d Mon Sep 17 00:00:00 2001 From: Henning Poettker Date: Wed, 22 Jan 2025 21:55:28 +0100 Subject: [PATCH] Time zone aware lenient parsing --- .../datatype/jsr310/deser/LocalDateDeserializer.java | 4 ++-- .../jsr310/deser/LocalDateTimeDeserializer.java | 6 ++---- .../datatype/jsr310/deser/LocalDateDeserTest.java | 10 ++++++++++ .../datatype/jsr310/deser/LocalDateTimeDeserTest.java | 6 +++--- 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/LocalDateDeserializer.java b/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/LocalDateDeserializer.java index dd33ce41..2a1b55cf 100644 --- a/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/LocalDateDeserializer.java +++ b/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/LocalDateDeserializer.java @@ -18,6 +18,7 @@ import java.io.IOException; import java.time.DateTimeException; +import java.time.Instant; import java.time.LocalDate; import java.time.format.DateTimeFormatter; @@ -161,8 +162,7 @@ protected LocalDate _fromString(JsonParser p, DeserializationContext ctxt, if (string.length() > 10 && string.charAt(10) == 'T') { if (isLenient()) { if (string.endsWith("Z")) { - return LocalDate.parse(string.substring(0, string.length() - 1), - DateTimeFormatter.ISO_LOCAL_DATE_TIME); + return Instant.parse(string).atZone(ctxt.getTimeZone().toZoneId()).toLocalDate(); } return LocalDate.parse(string, DateTimeFormatter.ISO_LOCAL_DATE_TIME); } diff --git a/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/LocalDateTimeDeserializer.java b/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/LocalDateTimeDeserializer.java index 79ccc35d..5d38175f 100644 --- a/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/LocalDateTimeDeserializer.java +++ b/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/LocalDateTimeDeserializer.java @@ -18,6 +18,7 @@ import java.io.IOException; import java.time.DateTimeException; +import java.time.Instant; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.Objects; @@ -195,13 +196,10 @@ protected LocalDateTime _fromString(JsonParser p, DeserializationContext ctxt, if (_formatter == DEFAULT_FORMATTER) { // ... only allow iff lenient mode enabled since // JavaScript by default includes time and zone in JSON serialized Dates (UTC/ISO instant format). - // And if so, do NOT use zoned date parsing as that can easily produce - // incorrect answer. if (string.length() > 10 && string.charAt(10) == 'T') { if (string.endsWith("Z")) { if (isLenient()) { - return LocalDateTime.parse(string.substring(0, string.length()-1), - _formatter); + return Instant.parse(string).atZone(ctxt.getTimeZone().toZoneId()).toLocalDateTime(); } JavaType t = getValueType(ctxt); return (LocalDateTime) ctxt.handleWeirdStringValue(t.getRawClass(), diff --git a/datetime/src/test/java/com/fasterxml/jackson/datatype/jsr310/deser/LocalDateDeserTest.java b/datetime/src/test/java/com/fasterxml/jackson/datatype/jsr310/deser/LocalDateDeserTest.java index e3fe9e92..b1317eda 100644 --- a/datetime/src/test/java/com/fasterxml/jackson/datatype/jsr310/deser/LocalDateDeserTest.java +++ b/datetime/src/test/java/com/fasterxml/jackson/datatype/jsr310/deser/LocalDateDeserTest.java @@ -9,6 +9,7 @@ import java.time.format.DateTimeParseException; import java.time.temporal.Temporal; import java.util.Map; +import java.util.TimeZone; import com.fasterxml.jackson.annotation.OptBoolean; import com.fasterxml.jackson.databind.cfg.CoercionAction; @@ -153,6 +154,15 @@ public void testDeserializationAsString03() throws Exception value); } + @Test + public void testDeserializationAsString04() throws Exception + { + ObjectReader reader = READER.with(TimeZone.getTimeZone(Z_BUDAPEST)); + Instant instant = Instant.parse("2024-07-21T22:00:00Z"); + LocalDate value = reader.readValue('"' + instant.toString() + '"'); + assertEquals("The value is not correct.", LocalDate.parse("2024-07-22"), value); + } + @Test public void testBadDeserializationAsString01() throws Throwable { diff --git a/datetime/src/test/java/com/fasterxml/jackson/datatype/jsr310/deser/LocalDateTimeDeserTest.java b/datetime/src/test/java/com/fasterxml/jackson/datatype/jsr310/deser/LocalDateTimeDeserTest.java index 3fb59fab..42d46a4a 100644 --- a/datetime/src/test/java/com/fasterxml/jackson/datatype/jsr310/deser/LocalDateTimeDeserTest.java +++ b/datetime/src/test/java/com/fasterxml/jackson/datatype/jsr310/deser/LocalDateTimeDeserTest.java @@ -261,14 +261,14 @@ public void testAllowZuluIfLenient() throws Exception // First, defaults: assertEquals("The value is not correct.", EXP, r.readValue(input)); - // but ensure that global timezone setting doesn't matter + // and ensure that global timezone setting matter LocalDateTime value = r.with(TimeZone.getTimeZone(Z_CHICAGO)) .readValue(input); - assertEquals("The value is not correct.", EXP, value); + assertEquals("The value is not correct.", EXP.minusHours(5), value); value = r.with(TimeZone.getTimeZone(Z_BUDAPEST)) .readValue(input); - assertEquals("The value is not correct.", EXP, value); + assertEquals("The value is not correct.", EXP.plusHours(2), value); } // [modules-java#94]: "Z" offset not allowed if strict mode