Рубрики
Без рубрики

Спящий режим – Отображение даты и времени

Узнайте, как правильно сопоставлять дату и время с помощью Hibernate.

Автор оригинала: baeldung.

1. введение

В этой статье мы покажем, как сопоставить значения временных столбцов в Hibernate, включая классы из пакетов java.sql , java.util и java.time .

2. Настройка проекта

Чтобы продемонстрировать отображение временных типов, нам понадобится база данных H2 и последняя версия библиотеки hibernate-core :


    org.hibernate
    hibernate-core
    5.4.12.Final


    com.h2database
    h2
    1.4.194

Для текущей версии библиотеки hibernate-core перейдите в репозиторий Maven Central .

3. Настройка часового пояса

При работе с датами рекомендуется установить определенный часовой пояс для драйвера JDBC. Таким образом, наше приложение будет независимым от текущего часового пояса системы.

Для нашего примера мы настроим его на основе каждого сеанса:

session = HibernateUtil.getSessionFactory().withOptions()
  .jdbcTimeZone(TimeZone.getTimeZone("UTC"))
  .openSession();

Другим способом было бы настроить свойство hibernate.jdbc.time_zone в файле свойств Hibernate, который используется для создания фабрики сеансов. Таким образом, мы могли бы указать часовой пояс один раз для всего приложения.

4. Сопоставление типов java.sql

Пакет java.sql содержит типы JDBC, которые соответствуют типам, определенным стандартом SQL:

  • Date соответствует типу DATE SQL, который является только датой без времени
  • Time соответствует типу TIME SQL, который представляет собой время суток, указанное в часах, минутах и секундах
  • Метка времени содержит информацию о дате и времени с точностью до наносекунд и соответствует типу МЕТКА ВРЕМЕНИ SQL

Поскольку эти типы соответствуют SQL, их сопоставление относительно прямолинейно. Мы можем использовать либо @Basic , либо @Column аннотацию:

@Entity
public class TemporalValues {

    @Basic
    private java.sql.Date sqlDate;

    @Basic
    private java.sql.Time sqlTime;

    @Basic
    private java.sql.Timestamp sqlTimestamp;

}

Затем мы могли бы установить соответствующие значения следующим образом:

temporalValues.setSqlDate(java.sql.Date.valueOf("2017-11-15"));
temporalValues.setSqlTime(java.sql.Time.valueOf("15:30:14"));
temporalValues.setSqlTimestamp(
  java.sql.Timestamp.valueOf("2017-11-15 15:30:14.332"));

Обратите внимание, что выбор java.sql типов для полей сущностей не всегда может быть хорошим выбором. Эти классы специфичны для JDBC и содержат много устаревших функций.

5. Отображение java.util.Тип даты

Тип java.util.Дата содержит информацию о дате и времени с точностью до миллисекунды. Но это не имеет прямого отношения к какому-либо типу SQL.

Вот почему нам нужна еще одна аннотация для указания нужного типа SQL:

@Basic
@Temporal(TemporalType.DATE)
private java.util.Date utilDate;

@Basic
@Temporal(TemporalType.TIME)
private java.util.Date utilTime;

@Basic
@Temporal(TemporalType.TIMESTAMP)
private java.util.Date utilTimestamp;

Аннотация @Temporal имеет единственное значение параметра типа TemporalType. Это может быть либо ДАТА , ВРЕМЯ или МЕТКА ВРЕМЕНИ , в зависимости от базового типа SQL, который мы хотим использовать для сопоставления.

Затем мы могли бы установить соответствующие поля следующим образом:

temporalValues.setUtilDate(
  new SimpleDateFormat("yyyy-MM-dd").parse("2017-11-15"));
temporalValues.setUtilTime(
  new SimpleDateFormat("HH:mm:ss").parse("15:30:14"));
temporalValues.setUtilTimestamp(
  new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS")
    .parse("2017-11-15 15:30:14.332"));

Как мы уже видели, | java.util.Дата тип (точность в миллисекундах) недостаточно точен для обработки значения метки времени (точность в наносекундах).

Поэтому, когда мы извлекаем сущность из базы данных, мы неудивительно найдем экземпляр java.sql.Timestamp в этом поле, даже если мы изначально сохраняли java.util.Дата :

temporalValues = session.get(TemporalValues.class, 
  temporalValues.getId());
assertThat(temporalValues.getUtilTimestamp())
  .isEqualTo(java.sql.Timestamp.valueOf("2017-11-15 15:30:14.332"));

Это должно быть хорошо для нашего кода, так как Метка времени расширяет Дату .

6. Отображение java.util.Тип календаря

Как и в случае с java.util.Дата , java.util.Тип календаря может быть сопоставлен с различными типами SQL, поэтому мы должны указать их с помощью @Temporal .

Единственное отличие заключается в том, что Hibernate не поддерживает отображение Calendar в ВРЕМЯ :

@Basic
@Temporal(TemporalType.DATE)
private java.util.Calendar calendarDate;

@Basic
@Temporal(TemporalType.TIMESTAMP)
private java.util.Calendar calendarTimestamp;

Вот как мы можем установить значение поля:

Calendar calendarDate = Calendar.getInstance(
  TimeZone.getTimeZone("UTC"));
calendarDate.set(Calendar.YEAR, 2017);
calendarDate.set(Calendar.MONTH, 10);
calendarDate.set(Calendar.DAY_OF_MONTH, 15);
temporalValues.setCalendarDate(calendarDate);

7. Отображение типов java.time

Начиная с Java 8, новый API даты и времени Java доступен для работы с временными значениями . Этот API исправляет многие проблемы java.util.Дата и java.util.Календарь занятия.

Типы из пакета java.time напрямую сопоставляются с соответствующими типами SQL. Поэтому нет необходимости явно указывать @Temporal аннотацию:

  • Локальные данные сопоставляются с ДАТОЙ
  • Местное время и Смещенное время сопоставляются с ВРЕМЯ
  • Instant , LocalDateTime , OffsetDateTime и ZonedDateTime сопоставляются с ОТМЕТКА ВРЕМЕНИ

Это означает, что мы можем пометить эти поля только аннотацией @Basic (или @Column ), как это:

@Basic
private java.time.LocalDate localDate;

@Basic
private java.time.LocalTime localTime;

@Basic
private java.time.OffsetTime offsetTime;

@Basic
private java.time.Instant instant;

@Basic
private java.time.LocalDateTime localDateTime;

@Basic
private java.time.OffsetDateTime offsetDateTime;

@Basic
private java.time.ZonedDateTime zonedDateTime;

Каждый временный класс в пакете java.time имеет статический метод parse() для анализа предоставленного значения String с использованием соответствующего формата. Итак, вот как мы можем установить значения полей сущностей:

temporalValues.setLocalDate(LocalDate.parse("2017-11-15"));

temporalValues.setLocalTime(LocalTime.parse("15:30:18"));
temporalValues.setOffsetTime(OffsetTime.parse("08:22:12+01:00"));

temporalValues.setInstant(Instant.parse("2017-11-15T08:22:12Z"));
temporalValues.setLocalDateTime(
  LocalDateTime.parse("2017-11-15T08:22:12"));
temporalValues.setOffsetDateTime(
  OffsetDateTime.parse("2017-11-15T08:22:12+01:00"));
temporalValues.setZonedDateTime(
  ZonedDateTime.parse("2017-11-15T08:22:12+01:00[Europe/Paris]"));

8. Заключение

В этой статье мы показали, как сопоставлять временные значения различных типов в режиме гибернации.

Исходный код статьи доступен на GitHub .