Я делаю несколько тестов, чтобы определить 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.
Как вы можете видеть, я добавил эту строку в 8:39 утра (Парижское GMT + 2), и отметки времени имеют хорошее значение UTC (6:38 утра). НО и local_time, и offset_time имеют странное значение (7:39 утра).
Интересно, почему такое поведение, если некоторые из вас понимают, почему мои два временных поля не хранят значения правильно.
PS: версия:
Мой образец 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;
моя вина. У меня правильно установлен "spring.jpa.properties.hibernate.jdbc.time_zone". Я вставляю свои данные с вызовом отдыха и репозиторием весенних данных, используя сущность "MyData"
Исправьте свойство, добавьте код и объясните, какие типы вы используете (Joda Time или JDK8).
ты прав, мне нужно добавить свою сущность, чтобы было понятнее. Как я уже сказал в начале поста, я использую только JDK8 Time API. Я хочу протестировать все типы JDK8, чтобы убедиться, что они будут правильно обрабатываться с параметром конфигурации UTC.




Попробуй:
@SpringBootApplication
public class YourApplication {
@PostConstruct
void started() {
// set JVM timezone as UTC
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
}
}
Это решение работает, но согласно: moelholm.com/2016/11/09/… «Это решение работает. Но оно очень агрессивно и имеет несколько потенциальных недостатков [...]», поэтому я предпочитаю решение для настройки гибернации.
было бы лучше использовать org.springframework.beans.factory.InitializingBean или даже org.springframework.context.event.ContextRefreshedEvent; org.springframework.context.event.EventListener; поскольку основаны на весеннем каркасе?
В случае, если решите использовать 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 это не работает.
Я открыл проблему в трекере ошибок гибернации и получил ответ на мою проблему.
Для 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
работает для меня.
После инициализации весеннего контекста ....
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.
Установка часового пояса по умолчанию в формате 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.
jpa.properties.hibernate.jdbc.time_zone= UTCдолжен бытьspring.jpa.properties.hibernate.jdbc.time_zone= UTC. В противном случае это не будет отображаться. Также КАК вы вставляете эти данные?