diff --git a/release-notes/CREDITS-2.x b/release-notes/CREDITS-2.x index 9f20c8f0..30cc2236 100644 --- a/release-notes/CREDITS-2.x +++ b/release-notes/CREDITS-2.x @@ -123,3 +123,8 @@ Joo Hyuk Kim (@JooHyukKim) (2.18.4) * Fixed #98: `JsonFormat` timezone attribute effect overwritten if pattern attribute present (2.19.1) + * Fixed #92: `DateTime` serialization result is not same as Java 8 `ZonedDateTime` + (2.20.0) + * Fixed #146: `DateTime` can't be serialized with its own zone + (2.20.0) + diff --git a/release-notes/VERSION-2.x b/release-notes/VERSION-2.x index a6f5871e..5bc4fb1b 100644 --- a/release-notes/VERSION-2.x +++ b/release-notes/VERSION-2.x @@ -6,6 +6,11 @@ Project: jackson-datatype-joda 2.20.0 (not yet released) +#92: `DateTime` serialization result is not same as Java 8 `ZonedDateTime` + (fixed by Joo-Hyuk K) +#146: `DateTime` can't be serialized with its own zone + (`WRITE_DATES_WITH_CONTEXT_TIME_ZONE` not respected) + (fixed by Joo-Hyuk K) - Generate SBOMs [JSTEP-14] 2.19.1 (not yet released) diff --git a/src/main/java/com/fasterxml/jackson/datatype/joda/cfg/JacksonJodaDateFormat.java b/src/main/java/com/fasterxml/jackson/datatype/joda/cfg/JacksonJodaDateFormat.java index 90a4fdcd..b24b646d 100644 --- a/src/main/java/com/fasterxml/jackson/datatype/joda/cfg/JacksonJodaDateFormat.java +++ b/src/main/java/com/fasterxml/jackson/datatype/joda/cfg/JacksonJodaDateFormat.java @@ -242,7 +242,23 @@ public DateTimeFormatter rawFormatter() { return _formatter; } + /** + * @deprecated since 2.20 Use {@link #createFormatter(SerializerProvider, DateTimeZone)} instead + */ + @Deprecated // since 2.20 public DateTimeFormatter createFormatter(SerializerProvider ctxt) + { + return createFormatter(ctxt, null); + } + + /** + * Creates a formatter with the specified timezone from the value if any. + * + * [dataformat-joda#92] DateTime serialization result is not same as Java 8 ZonedDateTime + * + * @since 2.20 + */ + public DateTimeFormatter createFormatter(SerializerProvider ctxt, DateTimeZone valueTimeZone) { DateTimeFormatter formatter = createFormatterWithLocale(ctxt); if (!_explicitTimezone) { @@ -251,6 +267,12 @@ public DateTimeFormatter createFormatter(SerializerProvider ctxt) formatter = formatter.withZone(DateTimeZone.forTimeZone(tz)); } } + if (!ctxt.isEnabled(SerializationFeature.WRITE_DATES_WITH_CONTEXT_TIME_ZONE)) { + if ((valueTimeZone != null) + && ((_jdkTimezone == null) || !valueTimeZone.toTimeZone().equals(_jdkTimezone))) { + formatter = formatter.withZone(valueTimeZone); + } + } return formatter; } diff --git a/src/main/java/com/fasterxml/jackson/datatype/joda/ser/DateTimeSerializer.java b/src/main/java/com/fasterxml/jackson/datatype/joda/ser/DateTimeSerializer.java index be2ffbf2..788b35a8 100644 --- a/src/main/java/com/fasterxml/jackson/datatype/joda/ser/DateTimeSerializer.java +++ b/src/main/java/com/fasterxml/jackson/datatype/joda/ser/DateTimeSerializer.java @@ -52,7 +52,7 @@ public void serialize(DateTime value, JsonGenerator gen, SerializerProvider prov if (numeric) { gen.writeNumber(value.getMillis()); } else { - gen.writeString(_format.createFormatter(provider).print(value)); + gen.writeString(_format.createFormatter(provider, value.getZone()).print(value)); } } else { // and then as per [datatype-joda#44], optional TimeZone inclusion diff --git a/src/test/java/com/fasterxml/jackson/datatype/joda/ser/DateTimeOwnZoneSerialization92Test.java b/src/test/java/com/fasterxml/jackson/datatype/joda/ser/DateTimeOwnZoneSerialization92Test.java new file mode 100644 index 00000000..5f46632d --- /dev/null +++ b/src/test/java/com/fasterxml/jackson/datatype/joda/ser/DateTimeOwnZoneSerialization92Test.java @@ -0,0 +1,40 @@ +package com.fasterxml.jackson.datatype.joda.ser; + +import java.util.TimeZone; + +import org.joda.time.DateTime; +import org.joda.time.DateTimeZone; +import org.junit.jupiter.api.Test; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.datatype.joda.JodaTestBase; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +// [dataformat-joda#92] DateTime serialization result is not same as Java 8 ZonedDateTime +public class DateTimeOwnZoneSerialization92Test + extends JodaTestBase +{ + private final ObjectMapper MAPPER = mapperWithModuleBuilder().disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS).build(); + + @Test + public void dateTimeShouldRetainItsOwnZone() throws Exception { + DateTime jodaZonedDateTime = new DateTime(2023, 10, 1, 12, 2, 3, 123, DateTimeZone.forID("Asia/Shanghai")); + + // without WRITE_DATES_WITH_CONTEXT_TIME_ZONE + assertEquals("\"2023-10-01T12:02:03.123+08:00\"", + MAPPER.writer() + .with(TimeZone.getTimeZone("UTC")) + .without(SerializationFeature.WRITE_DATES_WITH_CONTEXT_TIME_ZONE) + .writeValueAsString(jodaZonedDateTime)); + + // with WRITE_DATES_WITH_CONTEXT_TIME_ZONE + assertEquals("\"2023-10-01T04:02:03.123Z\"", + MAPPER.writer() + .with(TimeZone.getTimeZone("UTC")) + .with(SerializationFeature.WRITE_DATES_WITH_CONTEXT_TIME_ZONE) + .writeValueAsString(jodaZonedDateTime)); + } + +} \ No newline at end of file diff --git a/src/test/java/com/fasterxml/jackson/datatype/joda/tofix/DateTimeSerializationWithOffsets146Test.java b/src/test/java/com/fasterxml/jackson/datatype/joda/ser/DateTimeSerializationWithOffsets146Test.java similarity index 79% rename from src/test/java/com/fasterxml/jackson/datatype/joda/tofix/DateTimeSerializationWithOffsets146Test.java rename to src/test/java/com/fasterxml/jackson/datatype/joda/ser/DateTimeSerializationWithOffsets146Test.java index 151733ca..7fcec28e 100644 --- a/src/test/java/com/fasterxml/jackson/datatype/joda/tofix/DateTimeSerializationWithOffsets146Test.java +++ b/src/test/java/com/fasterxml/jackson/datatype/joda/ser/DateTimeSerializationWithOffsets146Test.java @@ -1,26 +1,25 @@ -package com.fasterxml.jackson.datatype.joda.tofix; +package com.fasterxml.jackson.datatype.joda.ser; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.datatype.joda.JodaTestBase; -import com.fasterxml.jackson.datatype.joda.testutil.failure.JacksonTestFailureExpected; import org.joda.time.*; -// [datatype-joda#146]: disable overwriting of timezone import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; -public class DateTimeSerializationWithOffsets146Test extends JodaTestBase +// [datatype-joda#146]: disable overwriting of timezone +public class DateTimeSerializationWithOffsets146Test + extends JodaTestBase { // [datatype-joda#146] - @JacksonTestFailureExpected @Test public void testLocalDateSerDefault() throws Exception { - final String inputStr = "2024-12-01T12:00:00+02:00"; + final String inputStr = "2024-12-01T12:00:00.000+02:00"; final DateTime inputValue = DateTime.parse(inputStr); final ObjectMapper mapper = mapperWithModuleBuilder() .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)