Вы можете указать шаблон с необязательным разделом (с разделителем []
), чтобы указать, что какое-либо поле является необязательным, и добавьте его в соответствующее поле, используя аннотацию @JsonFormat
.
Например, возьмем этот класс:
public class OptionalTimeZoneTest {
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ssXXX[ VV]")
private ZonedDateTime date;
// getter and setter
}
Обратите внимание на последнюю часть ([ VV]
): шаблон внутри []
является необязательным раздел, поэтому анализатор пытается разобрать его, если он присутствует. И картина VV
является зона идентификатор (или имя часового пояса в, для получения более подробной информации, посмотрите на javadoc)
С этим, в обоих форматах можно прочитать:
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
// add this to preserve the same offset (don't convert to UTC)
mapper.configure(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE, false);
// without timezone
String json = "{ \"date\": \"2016-07-26T05:30:47+01:00\" }";
OptionalTimeZoneTest value = mapper.readValue(json, OptionalTimeZoneTest.class);
System.out.println(value.getDate()); // 2016-07-26T05:30:47+01:00
// with timezone
json = "{ \"date\": \"2016-07-26T05:30:47+01:00 Europe/Paris\" }";
value = mapper.readValue(json, OptionalTimeZoneTest.class);
System.out.println(value.getDate()); // 2016-07-26T05:30:47+02:00[Europe/Paris]
Выход:
2016-07-26T05: 30: 47 + 01: 00
2016-07-26T05: 30: 47 + 02: 00 [Европа/Париж]
Обратите внимание, что в первом случае выход равен 2016-07-26T05:30:47+01:00
(поскольку он не имеет часовой пояс, поэтому применяется смещение +01:00
).
Но во втором случае выход 2016-07-26T05:30:47+02:00[Europe/Paris]
, потому что в Europe/Paris
часовом поясе, 26/07/2016 is summer-time (так что смещение является +02:00
). И API java.time
были реализованы таким образом, что временная зона имеет преимущество при анализе такого String
.
Если вы хотите, чтобы все ZonedDateTime
экземпляров должны быть преобразованы в UTC, вы можете удалить эту строку:
mapper.configure(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE, false);
Без него дата будет преобразована в UTC, а на выходе будет:
2016-07-26T04: 30: 47Z [UTC]
2016-07-26T03: 30: 47Z [UTC]
Термин «Европа/Париж» обозначает полный часовой пояс, включая любые истории перехода, фактические и будущие правила перехода на летнее время и версию базовых данных о часовом поясе. Поэтому сериализация и десериализация потенциально потребовали бы передать все это, а не только строку «Европа/Париж». На мой взгляд, сериализовать все не рекомендуется. Рассматривали ли вы только сериализацию момента «ZonedDateTime», обеспечивающего лучшую производительность? –