Дата часового пояса с весны загрузки и Джексона

Я разрабатываю весеннее загрузочное приложение, которое обрабатывает даты. Когда я отправляю объект назначения, который имеет startDateTime и endDateTime (Оба типа java.util.Date) Я отправляю такой формат:

{
    "lastName": "Jhon",
    "firstName": "Doe",
    "email": "jhon.doe@gmail.com",
    "description": "MyDescription",
    "startDateTime": "2017-10-09T22:43:07.109+0300",
    "endDateTime": "2017-10-09T21:40:07.109+0300",
}

Когда данные сохраняются в базе данных, они находятся в правильном часовом поясе, когда я пытаюсь получить свои данные обратно, они кажутся правильными, когда я отлаживаю, однако, после того, как Джексон их сериализует, у меня есть вывод с этими значениями:

"startDateTime": "2017-10-09T19:43:07.109+0000",
"endDateTime": "2017-10-09T18:40:07.109+0000",

Как я могу настроить Джексона для использования часового пояса, который поставляется с данными из моего хранилища?

------Обновить---------

Я попробовал ответ с OffsetDateTime но вывод довольно странный:

"startDateTime": {
        "offset": {
            "totalSeconds": 7200,
            "id": "+02:00",
            "rules": {
                "fixedOffset": true,
                "transitionRules": [],
                "transitions": []
            }
        },
        "month": "OCTOBER",
        "year": 2017,
        "hour": 21,
        "minute": 49,
        "nano": 654000000,
        "second": 15,
        "dayOfMonth": 9,
        "dayOfWeek": "MONDAY",
        "dayOfYear": 282,
        "monthValue": 10
    }

Я хотел бы иметь что-то вроде:

2017-10-09T22: 43: 07,109+0300

2 ответа

Решение

java.util.Date не имеет никакой информации о часовом поясе. После десериализации String к Date, смещение +0300 теряется: дата сохраняет только значение метки времени, и она не может знать, из какого исходного часового пояса она пришла.

Если выход всегда должен быть в +03:00 смещение, вы можете установить его непосредственно в соответствующих полях, используя com.fasterxml.jackson.annotation.JsonFormat аннотация:

@JsonFormat(timezone = "GMT+03:00")
private Date startDateTime;

@JsonFormat(timezone = "GMT+03:00")
private Date endDateTime;

При этом поля даты всегда будут сериализованы в +03:00 смещение:

{
  "startDateTime":"2017-10-09T22:43:07.109+0300",
  "endDateTime":"2017-10-09T21:40:07.109+0300"
}

Если входы могут быть в любом другом смещении (не только +03:00) и вы хотите сохранить его, java.util.Date не идеальный тип. Одной из альтернатив является использование модулей Jackson Java 8, если вы используете Java >= 8.

Для Java 6 и 7 есть ThreeTen Backport и соответствующий модуль Джексона - хотя я не тестировал, но код мог бы быть похожим, так как ThreeTen Backport содержит те же классы и методы, отличается только пакет - (в Java 8 это java.time а в ThreeTen Backport есть org.threeten.bp )

Чтобы сохранить дату, время и смещение, лучшей альтернативой является OffsetDateTime учебный класс. Так что вам просто нужно изменить тип полей и установить соответствующий формат:

@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXX")
private OffsetDateTime startDateTime;

@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXX")
private OffsetDateTime endDateTime;

В сопоставителе объектов вы также должны зарегистрировать JavaTimeModule и отключить ADJUST_DATES_TO_CONTEXT_TIME_ZONE особенность, поэтому смещения сохраняются (поведение по умолчанию заключается в преобразовании в часовой пояс контекста Джексона, который может не совпадать с используемым во входах - при отключении этого смещение сохраняется).

Вы можете использовать JacksonConfigurator (как объяснено в этом ответе) и сделайте эти конфигурации:

ObjectMapper om = new ObjectMapper();
om.registerModule(new JavaTimeModule());
om.configure(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE, false);

Этой конфигурации обычно достаточно, но вы также можете установить SerializationFeature.WRITE_DATES_AS_TIMESTAMPS в false на всякий случай.


Если вам все еще нужно работать с java.util.Date, вы можете использовать API для преобразования из / в него. В Java 8 есть новый Date.from метод:

// convert to java.util.Date
public Date getStartAsJavaUtilDate() {
    return Date.from(startDateTime.toInstant());
}

И в ThreeTen Backport есть org.threeten.bp.DateTimeUtils учебный класс:

// convert to java.util.Date
DateTimeUtils.toDate(startDateTime.toInstant());

Чтобы преобразовать Date вернуться к OffsetDateTime Впрочем, это сложнее. Date У объекта нет информации о часовом поясе, поэтому он не может знать исходное смещение. Один из вариантов - сохранить исходное смещение в отдельной переменной:

// keep the original offset
ZoneOffset startDateOffset = startDateTime.getOffset();

Затем вы можете преобразовать Date в Instant, а затем преобразовать его в исходное смещение:

// convert java.util.Date to original offset (Java 8)
startDateTime = date.toInstant().atOffset(startDateOffset);

// ThreeTen Backport
startDateTime = DateTimeUtils.toInstant(date).atOffset(startDateOffset);

Если вы используете чванство с весенней загрузкой, и ваша дата всегда сериализуется так долго. И SerializationFeature.WRITE_DATES_AS_TIMESTAMPS и spring.jackson.serialization.write -ates-as-timestamps=false не помогают ниже, решение сработало для меня. Добавьте его в свой класс с аннотацией @SpringBootApplication:

Проблема: значение SerializationFeature.WRITE_DATES_AS_TIMESTAMPS не читается из файла конфигурации Spring, который необходимо установить в false, чтобы скрыть длинное значение во время сериализации.

      @Autowired
private RequestMappingHandlerAdapter handlerAdapter;

@EventListener
public void handleContextRefresh(ContextRefreshedEvent event) {
    handlerAdapter
            .getMessageConverters()
            .stream()
            .forEach(c -> {
                if (c instanceof MappingJackson2HttpMessageConverter) {
                    MappingJackson2HttpMessageConverter jsonMessageConverter = (MappingJackson2HttpMessageConverter) c;
                    ObjectMapper objectMapper = jsonMessageConverter.getObjectMapper();
                    objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
                }
            });
}
Другие вопросы по тегам