I received a String field in a topic with date and offset and I need to convert this String to a LocalDateTime by adding the offset. For example, if I received:
2021-07-20T19:00:00.000 02:00
I want to convert in LocalDateTime:
2021-07-20T21:00:00.000
And I have a Bean with custom object mapper for this purpose:
@Configuration
public class MyConfiguration {
@Bean
public MyCustomObjectMapper configure() {
final ObjectMapper mapper = new ObjectMapper();
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSXXXXX");
final LocalDateTimeDeserializer dateTimeDeserializer = new LocalDateTimeDeserializer(formatter);
final LocalDateTimeSerializer dateTimeSerializer = new LocalDateTimeSerializer(formatter);
final JavaTimeModule javaTimeModule = new JavaTimeModule();
javaTimeModule.addDeserializer(LocalDateTime.class, dateTimeDeserializer);
javaTimeModule.addSerializer(LocalDateTime.class, dateTimeSerializer);
mapper.registerModule(javaTimeModule);
return new MyCustomObjectMapper (mapper);
}
}
But it doesn't work as I expect, since the resulting LocalDateTime offset disappears and is not added:
2021-07-20T19:00:00.000
How can I achieve this goal?
CodePudding user response:
The LocalDateTime
class is a date-time representation which is unaware of time zones and it's only logical that the LocalDateTimeDeserializer
ignores any time zone information in the source data.
To account for the time zone you could use the InstantDeserializer.OFFSET_DATE_TIME
deserializer (DateTimeFormatter.ISO_OFFSET_DATE_TIME
is actually the format of the source date time you have) and have its result converted to LocalDateTime
within a desired zone. This can be wrapped in a custom deserializer for ease of use, e.g.
class SmartLocalDateTimeDeserializer extends StdDeserializer<LocalDateTime> {
private final InstantDeserializer<OffsetDateTime> delegate = InstantDeserializer.OFFSET_DATE_TIME;
public SmartLocalDateTimeDeserializer() {
super(LocalDateTime.class);
}
@Override
public LocalDateTime deserialize(JsonParser p,
DeserializationContext ctxt) throws IOException, JsonProcessingException {
final OffsetDateTime result = delegate.deserialize(p, ctxt);
return result.atZoneSameInstant(ZoneId.systemDefault()).toLocalDateTime();
}
}
...
javaTimeModule.addDeserializer(LocalDateTime.class, new SmartLocalDateTimeDeserializer());