DateTimeFormatter.ISO_OFFSET_DATE_TIME not working as expected
DateTimeFormatter.ISO_OFFSET_DATE_TIME not working as expected
Based on this Java Date Time - OffsetDateTime.format() Examples article and this official documentation for DateTimeFormatter I would expect my OffsetDateTime to be serialized as 2011-12-03T10:15:30+00:00
where the offset the offset is +00:00
since its UTC.
2011-12-03T10:15:30+00:00
+00:00
I cannot manage to get the OffsetDateTime to render with an offset, it always just renders with the 'Z' Zulu. What am I doing wrong?
This is Spring Boot 2.0.0.RELEASE, and as you can see in the screenshot I've got the following modules on the class path and registered with the objectMapper, although I don't think that's relative because this issue seems to be directly with the DateTimeFormatter, my object mapper is just using the formatter I am giving it.
It does have an affect, because as you can see in the second screenshot when I specify the BASIC_ISO_FORMAT
it does produce a a different result.
BASIC_ISO_FORMAT
I do have this property set spring.jackson.date-format= com.fasterxml.jackson.databind.util.ISO8601DateFormat
in my application.properties but as I understand it, this has no affect on OffsetDateTime it only supports the legacy Date objects from previous version of java. Incidentally changing this seems to have no affect as expected.
spring.jackson.date-format= com.fasterxml.jackson.databind.util.ISO8601DateFormat
Any help would be appreciated.
Using ISO_ZONED_DATE_TIME format...
Using BASIC_ISO_FORMAT... this does have an affect so I know the formatter is doing something, I'm just not clear why the ISO_ZONED_DATE_TIME is not rendered as expected.
this.objectMapper = objectMapperBuilder.build()
.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE)
.disable(SerializationFeature.INDENT_OUTPUT)
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.disable(SerializationFeature.WRITE_DATES_WITH_ZONE_ID);
SimpleModule simpleModule = new SimpleModule();
simpleModule.addSerializer(OffsetDateTime.class, new JsonSerializer<OffsetDateTime>() {
@Override
public void serialize(OffsetDateTime offsetDateTime, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
String formattedDate = DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(offsetDateTime);
jsonGenerator.writeString(formattedDate);
}
});
this.objectMapper.registerModule(simpleModule);
OffsetDateTime now = OffsetDateTime.now();
TimeZone defaultTimeZone = TimeZone.getDefault();
ZoneId defautlZoneOffset = ZoneOffset.systemDefault();
String serializedOffsetDateTime = this.objectMapper.writeValueAsString(now);
//returns -> "2018-06-27T11:45:56.035Z"
If you’ll be so kind to post your code examples as text (nicely formatted), I will consider copy-pasting it and modifying it for an answer.
– Ole V.V.
Jun 28 at 10:25
@OleV.V. I'v updated the question with formatted code. I do not think this is a duplicate for a very specific reason. I'm not using a custom pattern. I'm explicitly using
DateTimeFormatter.ISO_OFFSET_DATE_TIME
with an OffsetDateTime.java
object. The documentation clearly states that this format should be 2011-12-03T10:15:30+01:00'
. While I am sure that the cause of both issues is the same.– eztinkerdreams
Jun 28 at 13:06
DateTimeFormatter.ISO_OFFSET_DATE_TIME
OffsetDateTime.java
2011-12-03T10:15:30+01:00'
updated to change expected value to `+00:00' which was my original intent, it was a typo.
– eztinkerdreams
Jun 28 at 17:57
Please post source code as text, not screenshots.
– Basil Bourque
2 days ago
2 Answers
2
Feature, not a bug
The documentation for DateTimeFormatter. ISO_OFFSET_DATE_TIME
tells you to expect a Z
rather than a +00:00
when using an offset of zero (UTC itself).
DateTimeFormatter. ISO_OFFSET_DATE_TIME
Z
+00:00
That doc says:
The format consists of:
• The ISO_LOCAL_DATE_TIME
• The offset ID.
Follow the link for that second item, offset ID. That page says:
There are three formats:
• Z - for UTC (ISO-8601)
• +hh:mm or -hh:mm - if the seconds are zero (ISO-8601)
• +hh:mm:ss or -hh:mm:ss - if the seconds are non-zero (not ISO-8601)
The Z
is part of the ISO 8601 standard. Any decent date-time library should be able to parse a string with Z
.
Z
Z
If you insist on +00:00
rather than the more common Z
, you will need to specify a custom formatting pattern as discussed in the Question linked by Ole V.V.
+00:00
Z
No such thing as -00:00
-00:00
offset is -00:00 since its UTC.
Your use of -00:00
in the Question is incorrect. The ISO 8601 standard specifically forbids such a value. The offset for UTC itself is a positive zero, not negative zero: +00:00
.
-00:00
+00:00
There is RFC 3339 which proclaims itself to be a “profile” of ISO 8601. The RFC violates ISO 8601 in allowing the use of -00:00
, and assigning it the meaning of an unknown offset. A very poor and unwise choice, IMHO, confusing and unneeded. ISO 8601 already accounts for an unknown offset: Just omit the offset notation entirely.
-00:00
I recommend avoiding both this practice of negative zero and that RFC 3339.
Exceptional answer, I understand completely now that there are actually two different objects that need to be formatted, and I just simply missed the information you mentioned in the secondary documentation. thanks. thanks to @OleV.V. who also provided the same answer, but less explicitly.
– eztinkerdreams
Jun 28 at 17:59
For future reference. Amazon's AWS Athena service is having issues parsing standard ISO-8601 dates right now. I'm sure the issue will get resolve eventually, for now we are having to work around the issue. ``` "HIVE_BAD_DATA: Error parsing field value '2017-11-01T00:00:00Z' for field 6: For input string: "2017-11-01T00:00:00Z" ```
– eztinkerdreams
Jun 28 at 18:05
As you are aware, formatting offset zero (or Zulu) as Z
ought to work. It’s part of the standard format you are using, ISO 8601. However, in case it doesn’t:
Z
static DateTimeFormatter formatter
= DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ssxxx");
@Override
public void serialize(OffsetDateTime offsetDateTime, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
String formattedDate = formatter.format(offsetDateTime);
jsonGenerator.writeString(formattedDate);
}
This will serialize the OffsetDateTime
as for example 2011-12-03T10:14:30+00:00
(which is allowed within the standard as well). Lowercase x
in the format pattern string formats the offset without resorting to Z
for offset zero.
OffsetDateTime
2011-12-03T10:14:30+00:00
x
Z
The above is the short and straightforward declaration of the formatter. Since I like to rely on higher-level standard elements where I can, I would consider the longer variant:
static DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
.appendPattern("xxx")
.toFormatter();
This reuses ISO_LOCAL_DATE_TIME
from the standard library. If your time doesn’t have a fraction of second, the output will be the same. If it has, it will be included in the serialization in the latter case, just as it would with ISO_OFFSET_DATE_TIME
, for example 2011-12-03T10:14:30.1234+00:00
.
ISO_LOCAL_DATE_TIME
ISO_OFFSET_DATE_TIME
2011-12-03T10:14:30.1234+00:00
LInk: Wikipedia article: ISO 8601
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
Possible duplicate of How to make ZoneOffset UTC return "+00:00" instead of "Z"
– Ole V.V.
Jun 28 at 10:21