Спящий режим + дата магазина весенней загрузки при проблемах с часовым поясом UTC

Я делаю несколько тестов, чтобы определить UTC как часовой пояс по умолчанию для моего приложения. Прежде всего, я хочу, чтобы мои значения datetime сохранялись в формате UTC.

Согласно VLAD MIHALCEA (https://vladmihalcea.com/how-to-store-date-time-and-timestamps-in-utc-time-zone-with-jdbc-and-hibernate/) и https://moelholm.com/2016/11/09/spring-boot-controlling-timezones-with-hibernate/ я установил в своем файле свойств:

spring.jpa.properties.hibernate.jdbc.time_zone= UTC

Для тестирования я использую базу данных h2, я создал образец объекта со всеми типами dateTime java 8.

В моей конфигурации Liquibase они определены так:

<column name = "instant" type = "timestamp"/>
<column name = "local_date" type = "date"/>
<column name = "local_time" type = "time"/>
<column name = "offset_time" type = "time"/>
<column name = "local_date_time" type = "timestamp"/>
<column name = "offset_date_time" type = "timestamp"/>
<column name = "zoned_date_time" type = "timestamp"/>

Думаю, я использую хороший шрифт для всех полей. Это работает для всех полей, кроме «local_time» «offset_time», которые являются типами Time sql, а не timestamp.

Спящий режим + дата магазина весенней загрузки при проблемах с часовым поясом UTC

Как вы можете видеть, я добавил эту строку в 8:39 утра (Парижское GMT ​​+ 2), и отметки времени имеют хорошее значение UTC (6:38 утра). НО и local_time, и offset_time имеют странное значение (7:39 утра).

Интересно, почему такое поведение, если некоторые из вас понимают, почему мои два временных поля не хранят значения правильно.

PS: версия:

  • Гибернация: 5.2.17.Final
  • Пружинная загрузка: 2.0.4.RELEASE

Мой образец Entity используется для вставки данных:

import javax.persistence.*;
import java.io.Serializable;
import java.time.*;
import java.util.Objects;

@Entity
@Table(name = "avdev_myData")
public class MyData implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
    @SequenceGenerator(name = "sequenceGenerator")
    private Long id;

    @Column(name = "name")
    private String name;

    @Column(name = "instant")
    private Instant instant;

    @Column(name = "local_date")
    private LocalDate localDate;

    @Column(name = "local_time")
    private LocalTime localTime;

    @Column(name = "offset_time")
    private OffsetTime offsetTime;

    @Column(name = "local_date_time")
    private LocalDateTime localDateTime;

    @Column(name = "offset_date_time")
    private OffsetDateTime offsetDateTime;

    @Column(name = "zoned_date_time")
    private ZonedDateTime zonedDateTime;
jpa.properties.hibernate.jdbc.time_zone= UTC должен быть spring.jpa.properties.hibernate.jdbc.time_zone= UTC. В противном случае это не будет отображаться. Также КАК вы вставляете эти данные?
M. Deinum 17.09.2018 11:52

моя вина. У меня правильно установлен "spring.jpa.properties.hibernate.jdbc.time_zone". Я вставляю свои данные с вызовом отдыха и репозиторием весенних данных, используя сущность "MyData"

Avdev4j 17.09.2018 11:58

Исправьте свойство, добавьте код и объясните, какие типы вы используете (Joda Time или JDK8).

M. Deinum 17.09.2018 11:59

ты прав, мне нужно добавить свою сущность, чтобы было понятнее. Как я уже сказал в начале поста, я использую только JDK8 Time API. Я хочу протестировать все типы JDK8, чтобы убедиться, что они будут правильно обрабатываться с параметром конфигурации UTC.

Avdev4j 17.09.2018 12:05
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
5
4
17 076
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 6

Попробуй:

@SpringBootApplication
public class YourApplication {

    @PostConstruct
    void started() {
        // set JVM timezone as UTC
        TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
    }
}

Это решение работает, но согласно: moelholm.com/2016/11/09/… «Это решение работает. Но оно очень агрессивно и имеет несколько потенциальных недостатков [...]», поэтому я предпочитаю решение для настройки гибернации.

Avdev4j 17.09.2018 12:10

было бы лучше использовать org.springframework.beans.factory.InitializingBean или даже org.springframework.context.event.ContextRefreshedEvent; org.springframework.context.event.EventListener; поскольку основаны на весеннем каркасе?

Tiago Medici 31.05.2019 14:58

В случае, если решите использовать MySQL, в моем случае работает правильно с

spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL57InnoDBDialect

spring.datasource.url=jdbc:mysql://DBHOST:3306/DBNAME?useLegacyDatetimeCode=false&serverTimezone=UTC

Работает ли он со столбцами "time" sql? Потому что это моя проблема. Я буду тестировать с mysql, но и с h2, и с postgres это не работает.

Avdev4j 19.09.2018 10:39
Ответ принят как подходящий

Я открыл проблему в трекере ошибок гибернации и получил ответ на мою проблему.

Для LocalTime преобразование относится к 1 января 1970 года, а не к тому дню, когда я проводил тест. Таким образом, DST не обрабатывается.

По словам Влада Михалчи, мы должны использовать LocalDateTime вместо этого, потому что мы знаем дату и, конечно, находится ли он в периоде летнего времени или нет.

здесь есть полный ответ: https://hibernate.atlassian.net/browse/HHH-12988?focusedCommentId=103750&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#comment-103750

С уважением

spring.datasource.url=jdbc:mysql://...?serverTimezone=Asia/Shanghai

работает для меня.

  1. Hibernate ДОЛЖЕН отражать часовой пояс mysql.
  2. mysql jdbc должен отражать часовой пояс mysql.

После инициализации весеннего контекста ....

import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;


@Component
public class ApplicationStartUp {

    @EventListener(ContextRefreshedEvent.class)
    public void contextRefreshedEvent() {

        TimeZone.setDefault(TimeZone.getTimeZone("UTC"));

    }   

}

ИЛИ

@Component
public class InitializingContextBean implements InitializingBean {

    private static final Logger LOG  = Logger.getLogger(InitializingContextBean.class);

    @Autowired
    private Environment environment;

    @Override
    public void afterPropertiesSet() throws Exception {         
            TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
    }
}

Я полагаю, что, делая это, вы теряете приятные функции, такие как преобразование часового пояса системы по умолчанию в UTC. Затем каждый раз вам нужно будет указать, в каком часовом поясе есть LocalDateTime, который вы конвертируете в UTC.

funder7 26.06.2020 16:21

Установка часового пояса по умолчанию в формате UTC не решила полностью мою проблему. Это принесло еще одну проблему: когда я записал объект со свойством OffsetTime, он неправильно принял информацию о смещении и сохраненные данные. Например, 18: 25 + 03: 00 превращается в 18: 25 + 00: 00. Я думаю, что это худший сценарий, потому что данные будут повреждены.

Чтобы преодолеть эту проблему и не потерять информацию о смещении, я использовал метод withOffsetSameInstant класса OffsetTime и записал свою сущность таким образом.

ZoneOffset systemZoneOffset = ZoneId.systemDefault().getRules().getOffset(Instant.now());
OffsetTime offsetTime = clientOffsetTime.withOffsetSameInstant(systemZoneOffset);

Наконец, это будет работать для любого часового пояса, который использует ваш компьютер. Это также должно работать для свойств типа OffsetDateTime.

Другие вопросы по теме