One alternative is to create a custom deserializer. First you annotate the respective field:
@JsonDeserialize(using = OffsetDateTimeDeserializer.class)
private OffsetDateTime date;
And then you create the deserializer. It uses a java.time.format.DateTimeFormatterBuilder
, using lots of optional sections to deal with all the different types of offsets:
public class OffsetDateTimeDeserializer extends JsonDeserializer<OffsetDateTime> {
private DateTimeFormatter fmt = new DateTimeFormatterBuilder()
// date/time
.append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
// offset (hh:mm - "+00:00" when it's zero)
.optionalStart().appendOffset("+HH:MM", "+00:00").optionalEnd()
// offset (hhmm - "+0000" when it's zero)
.optionalStart().appendOffset("+HHMM", "+0000").optionalEnd()
// offset (hh - "+00" when it's zero)
.optionalStart().appendOffset("+HH", "+00").optionalEnd()
// offset (pattern "X" uses "Z" for zero offset)
.optionalStart().appendPattern("X").optionalEnd()
// create formatter
.toFormatter();
@Override
public OffsetDateTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
return OffsetDateTime.parse(p.getText(), fmt);
}
}
I also used the built-in constant DateTimeFormatter.ISO_LOCAL_DATE_TIME
because it takes care of the optional fraction of seconds - and the number of fractional digits seems to be variable as well, and this built-in formatter already takes care of those details for you.
I'm using JDK 1.8.0_144 and found a shorter (but not much) solution:
private DateTimeFormatter fmt = new DateTimeFormatterBuilder()
// date/time
.append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
// offset +00:00 or Z
.optionalStart().appendOffset("+HH:MM", "Z").optionalEnd()
// offset +0000, +00 or Z
.optionalStart().appendOffset("+HHmm", "Z").optionalEnd()
// create formatter
.toFormatter();
Another improvement you can make is change the formatter to be static final
, because this class is immutable and thread-safe.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…