-
Notifications
You must be signed in to change notification settings - Fork 117
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Normalize zone id during ZonedDateTime deserialization #267
Normalize zone id during ZonedDateTime deserialization #267
Conversation
Might have to tweak the solution, thought of another test case and this should probably pass also @Test
public void testDeserializationComparedToStandard2() throws Throwable
{
String inputString = "2021-02-01T19:49:04.0513486Z[UTC]";
assertEquals("The value is not correct.",
DateTimeFormatter.ISO_ZONED_DATE_TIME.parse(inputString, ZonedDateTime::from),
READER.readValue(q(inputString)));
}
|
Summary of this as it stands:
In InstantDeserializer the timezone adjustment happens by default (again, desired behavior). if (shouldAdjustToContextTimezone(ctxt)) {
return adjust.apply(value, getZone(ctxt));
}
private ZoneId getZone(DeserializationContext context)
{
// Instants are always in UTC, so don't waste compute cycles
return (_valueClass == Instant.class) ? null : context.getTimeZone().toZoneId();
} From here there are two possible paths.
Why does this happen? Review the output of the following calls. toZoneId() System.out.println(TimeZone.getTimeZone("UTC").toZoneId()); // UTC
System.out.println(TimeZone.getTimeZone(ZoneOffset.UTC).toZoneId()); // UTC
System.out.println(TimeZone.getTimeZone("Z").toZoneId()); // GMT
System.out.println(TimeZone.getTimeZone("GMT").toZoneId()); // GMT normalized() System.out.println(TimeZone.getTimeZone("UTC").toZoneId().normalized()); // Z
System.out.println(TimeZone.getTimeZone(ZoneOffset.UTC).toZoneId().normalized()); // Z
System.out.println(TimeZone.getTimeZone("Z").toZoneId().normalized()); // Z
System.out.println(TimeZone.getTimeZone("GMT").toZoneId().normalized()); // Z ZonedDateTimes with adjustments String inputString = "2021-02-01T19:49:04.0513486Z";
ZonedDateTime standard = DateTimeFormatter.ISO_ZONED_DATE_TIME.parse(inputString, ZonedDateTime::from);
System.out.println(standard.withZoneSameInstant(ZoneId.of("UTC"))); // 2021-02-01T19:49:04.051348600Z[UTC]
System.out.println(standard.withZoneSameInstant(ZoneId.of("GMT"))); // 2021-02-01T19:49:04.051348600Z[GMT]
System.out.println(standard.withZoneSameInstant(ZoneId.of("Z"))); // 2021-02-01T19:49:04.051348600Z Fundamentally, there is a disconnect between UTC and GTM here. When the Zone Ids are normalized, all 4 produce the same result, which is consistent with the ISO standard. The question then boils down to this: If the consumer has set their TimeZone manually to GMT, would they want their ZoneDateTime objects to all say Reference: FasterXML/jackson-databind#915 I would strongly advocate for changing the default behavior. If needed, I suppose a DeserializationFeature could be implemented to disable normalization of the ZoneId if by the off chance someone is relying on the existing behavior, but it should be opted into during an upgrade. With normalization on by default, failure of the test case I posted above is expected. With ADJUST_DATES_TO_CONTEXT_TIME_ZONE enabled, the new behavior would be that it is adjusted to a normalized zone. To read that string in with the zone set to the non-normalized UTC zone, the following test case would work. If a DeserializationFeature to disable normalization were implemented, that could also be used to achieve the desired result. @Test
public void testDeserializationComparedToStandard2() throws Throwable
{
String inputString = "2021-02-01T19:49:04.0513486Z[UTC]";
ZonedDateTime converted = newMapper()
.configure(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE, false)
.readerFor(ZonedDateTime.class).readValue(q(inputString));
assertEquals("The value is not correct.",
DateTimeFormatter.ISO_ZONED_DATE_TIME.parse(inputString, ZonedDateTime::from),
converted);
} Hopefully this now paints a complete picture, since the issue was pretty obscure to start with. What are your thoughts @cowtowncoder? |
Hmmh. Ok, this change fails a ton of tests; I can't quite judge if this is expected (some are, probably, but all)? |
I'll check, the tests passed locally |
I believe the failures are due to the system defaults on the linux box running the test. I'll see if I can mock the environment locally and figure out what it's returning. All the tests pass on my local Windows 11 (EST zone). |
That change should fix it. The GitHub runner's system zone is UTC. It worked for me locally because EST normalized is still EST. |
@dscalzi Ok great. So, just one more thing wrt merging this: if I haven't yet asked for CLA, from: https://github.com/FasterXML/jackson/blob/master/contributor-agreement.pdf I would need that submitted before merging. Only needs to be done once before the first contribution. Looking forward to merging! |
Just sent, and added a couple notes to the PR |
@@ -324,7 +324,9 @@ protected T _fromDecimal(DeserializationContext context, BigDecimal value) | |||
private ZoneId getZone(DeserializationContext context) | |||
{ | |||
// Instants are always in UTC, so don't waste compute cycles | |||
return (_valueClass == Instant.class) ? null : context.getTimeZone().toZoneId(); | |||
// Normalizing the zone to prevent discrepancies. | |||
// See https://github.com/FasterXML/jackson-modules-java8/pull/267 for details |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good, I like references like this!
Thank you again @dscalzi ! Merged in for inclusion in 2.15.0. |
Hi @dscalzi ! I just noticed a new failure in https://github.com/FasterXML/jackson-integration-tests/ (when starting to prepare for upcoming 2.15.0-rc1 release) where it looks like timezone marker
but I can "fix" it by changing |
hey @cowtowncoder, could you try replacing ZoneId.of("UTC") with ZoneOffset.UTC? |
Sure, will do (and now I wonder if that wasn't the one already). |
@dscalzi yes, that fixes it. Thank you! |
This is triggered by an Jackson update. See FasterXML/jackson-modules-java8#204 and FasterXML/jackson-modules-java8#267
* Dep bumps, fjernet jitpack, gradle bump * Erstattet ZoneId med ZoneOffSet FasterXML/jackson-modules-java8#267 * Lagt tilbake jitpack
Disable failing tests - Refs ThreeTen/threetenbp#185 - Refs FasterXML/jackson-modules-java8#132 - Refs FasterXML/jackson-modules-java8#267
….2 (#139) Disable failing tests - Refs ThreeTen/threetenbp#185 - Refs FasterXML/jackson-modules-java8#132 - Refs FasterXML/jackson-modules-java8#267
….2 (#139) Disable failing tests - Refs ThreeTen/threetenbp#185 - Refs FasterXML/jackson-modules-java8#132 - Refs FasterXML/jackson-modules-java8#267
This change does seem to have broken our application. There are many places where we're comparing ZonedDateTime fields deserialized from stored JSON strings (format written out: "2023-02-02T20:23:11.057Z"), to ZonedDateTime objects created in code with ZoneId.of("UTC") . Fixing seems to mean replacing anywhere in code using ZoneId "UTC" with the offset zone Z, but that's a lot of application code to go through. Would be nice to have a way of disabling normalization! org.opentest4j.AssertionFailedError: |
@indyana If you'd like to see configurability, please file a new issue as RFE, asking for configurability, referencing back to this issue. Then if anyone has time and interest they could work on adding this feature -- it does sound useful. One practical complication here is just that module does not yet have configurability, so would probably need to add a |
@indyana Depending on your usage, it would largely just be a find/replace of ZoneId.of("UTC") with ZoneOffset.UTC as you mentioned. |
Yep, I understand, just a good number of repos to go through to fix the issue and honestly the behavior isn't what I would expect if I specifically configure Jackson to adjust dates to time zone UTC. |
Resolves #204
https://stackoverflow.com/a/39507023/5295111
https://docs.oracle.com/javase/8/docs/api/java/time/ZoneId.html#normalized--