Стойността OffsetDateTime се променя при извличане от базата данни

Използвам таблица от MS SQL база данни и разработих GET API, използвайки Spring Boot, за да извлека всички данни от тази таблица.
Тук таблицата съдържа колона от тип datetimeoffset(7).

Имам член на данни OffsetDateTime updatedDate в моя обект, използван за картографиране на datetimeoffset колона от DB

Сега, когато получа отговора на API, виждам, че стойността updatedDate (2021-06-17T05:37:40.1938687+05:30) е различна от действителната стойност на базата данни (2021-06- 16 19:07:40.1938687 -05:00).

Разгледах мрежата, за да намеря малко помощ, и опитах няколко решения, подобни на Решение, но не видях никакви положителни резултати.

Всяка помощ би била наистина ценна, благодаря!

PS. Spring Boot версия: 2.3.1.RELEASE


person Vishal    schedule 09.07.2021    source източник


Отговори (2)


Тези две стойности представляват точно една и съща точка на времевата линия. Те просто са представени в различни часови зони: базата данни използва EST, а Spring приложението използва IST Indian. Когато ги конвертираме в GMT, те ще изглеждат по същия начин:

String[] dates = {"2021-06-17T05:37:40.1938687 +05:30", "2021-06-16T19:07:40.1938687 -05:00"};
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.n XXX")
        .withZone(ZoneId.of("GMT"));
Arrays.stream(dates)
        .map(date -> formatter.format(OffsetDateTime.parse(date, formatter)))
        .forEach(System.out::println);

Горният код отпечатва:

2021-06-17T00:07:40.1938687 Z
2021-06-17T00:07:40.1938687 Z

Ако искате да запазите оригиналното представяне, трябва да инструктирате да използвате EST часова зона вместо стандартна или системна. Опитайте да зададете: spring.jackson.time-zone свойство в конфигурационния файл:

Часова зона, използвана при форматиране на дати. Например Америка/Лос_Анджелис или GMT+10.

person Michał Ziober    schedule 10.07.2021
comment
Благодаря за отговора Добавих свойството spring.jackson.time-zone в application.properties със стойност като GMT-5, но все още виждам същия резултат. Трябва ли да направя някаква друга допълнителна конфигурация, свързана с jackson, освен публикацията stackoverflow.com/questions/46653455/ - person Vishal; 11.07.2021
comment
@Vishal, коя версия на Jackson използваш? Създадохте ли свой собствен екземпляр на ObjectMapper или използвате общ, създаден от Spring? Как работи, когато създадете тестов контролер и върнете нов екземпляр на OffsetDateTime? - person Michał Ziober; 11.07.2021
comment
Използвам Jackson версия като 2.11.0 и да, предоставих персонализиран екземпляр на ObjectMapper, където изрично деактивирам WRITE_DATES_AS_TIMESTAMPS и ADJUST_DATES_TO_CONTEXT_TIME_ZONE Когато върна нов екземпляр на OffsetDateTime, виждам, че има IST зона - person Vishal; 11.07.2021
comment
Здравей Михал, между другото, когато изпратя OffsetDateTime екземпляр с различен ZoneOffset, виждам правилно новата зона в отговора на API. Например, OffsetDateTime now = OffsetDateTime.now(); now = now.withOffsetSameInstant(ZoneOddset.of("-05:30"); return now; имам нужда Джаксън да направи това за мен. - person Vishal; 11.07.2021
comment
@Vishal, опитай също така да провериш как изглежда OffsetDateTime, когато се зарежда от база данни. Използвате ли Hibernate или някое друго ORM? Разгледайте Hibernate не съхранява правилно ZonedDateTime като datetimeoffset в SQL сървър - person Michał Ziober; 11.07.2021
comment
дори след като опитах по-горе, все още съм на същата страница - person Vishal; 13.07.2021

Сега, когато получа отговора на API, виждам, че стойността на updatedDate (2021-06-17T05:37:40.1938687+05:30) е различна от действителната стойност на базата данни (2021-06-16 19:07:40.1938687 -05:00 ).

Не, и датата-час представляват един и същ миг/момент.

Демо:

import java.time.Instant;

public class Main {
    public static void main(String[] args) {
        System.out.println(Instant.parse("2021-06-17T05:37:40.1938687+05:30"));
        System.out.println(Instant.parse("2021-06-16T19:07:40.1938687-05:00"));
    }
}

Изход:

2021-06-17T00:07:40.193868700Z
2021-06-17T00:07:40.193868700Z

ОНЛАЙН ДЕМО

Можете да конвертирате един в друг

Използване на OffsetDateTime#withOffsetSameInstant< /a>, можете да конвертирате един в друг.

Демо:

import java.time.OffsetDateTime;
import java.time.ZoneOffset;

public class Main {
    public static void main(String[] args) {
        OffsetDateTime odtFromResponse = OffsetDateTime.parse("2021-06-17T05:37:40.1938687+05:30");

        OffsetDateTime odtDesired = odtFromResponse.withOffsetSameInstant(ZoneOffset.of("-05:00"));
        System.out.println(odtDesired);
    }
}

Изход:

2021-06-16T19:07:40.193868700-05:00

ОНЛАЙН ДЕМО

Научете повече за съвременния API за дата-час от Trail: Date Time.

person Arvind Kumar Avinash    schedule 10.07.2021
comment
Да, мога да разбера, че датите са абсолютно равни, просто часовата зона е различна. Не искам Джаксън да преобразува датата от EST в IST, за което зададох конфигурацията (споменато в публикация stackoverflow.com/questions/46653455/). Въпреки това все още виждам, че извлечената дата съдържа IST часова зона, а не EST - person Vishal; 11.07.2021
comment
@Vishal – Опитайте @JsonFormat(shape=JsonFormat.Shape.STRING, pattern="uuuu-MM-dd'T'HH:mm:ss.SSSSSSSSSXXX", timezone="America/Chicago") OffsetDateTime updatedDate и ми кажете дали е решил проблема ви. Променете часовата зона според часовата зона на вашия DB сървър. - person Arvind Kumar Avinash; 11.07.2021
comment
Здравей Арвинд, след като направих предложените промени, все още виждам същата часова зона. Трябва ли да спра предоставянето на персонализирана реализация на ObjectMapper? JFYI, OffsetDateTime член е вътре @Entity, където съм използвал @JsonFormat анотация. - person Vishal; 11.07.2021
comment
@Vishal - От другия ви коментар забелязах, че вече сте внедрили персонализиран ObjectMapper. Случайно опитахте ли предложението в този коментар? - person Arvind Kumar Avinash; 11.07.2021
comment
Здравей Арвинд, вече опитах това, но без успех. Едно решение на моя проблем е да направя часовата зона на JVM и часовата зона на DB еднакви. Например, използвайки JVM аргумент -Duser.timezone=US/Central. Това помага за решаването на този проблем. В моя случай обаче не искам да правя приложението Spring Boot зависимо от часовата зона на базата данни. - person Vishal; 11.07.2021