Перейти к основному содержимому

Спящий режим — сопоставление даты и времени

· 4 мин. чтения

Задача: Сумма двух

Дано массив целых чисел и целая сумма. Нужно найти индексы двух чисел, сумма которых равна заданной ...

ANDROMEDA

1. Введение

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

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

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

<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.4.12.Final</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.194</version>
</dependency>

Текущую версию библиотеки 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:

  • Дата соответствует типу SQL DATE , который представляет собой только дату без времени.
  • Время соответствует типу SQL TIME , который представляет собой время дня, указанное в часах, минутах и секундах.
  • Отметка времени включает информацию о дате и времени с точностью до наносекунд и соответствует SQL-типу TIMESTAMP .

Поскольку эти типы соответствуют 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.Date

Тип java.util.Date содержит информацию о дате и времени с точностью до миллисекунды. Но это не имеет прямого отношения к какому-либо типу 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. Это может быть DATE , TIME или TIMESTAMP , в зависимости от базового типа 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.Date (с точностью до миллисекунд) недостаточно точен для обработки значения Timestamp (с точностью до наносекунд).

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

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

Это должно подойти для нашего кода, поскольку Timestamp расширяет Date .

6. Сопоставление типа java.util.Calendar

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

Единственное отличие состоит в том, что Hibernate не поддерживает сопоставление Calendar с TIME :

@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, новый Java Date and Time API доступен для работы с временными значениями . Этот API устраняет многие проблемы классов java.util.Date и java.util.Calendar .

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

  • LocalDate сопоставляется с DATE
  • LocalTime и OffsetTime сопоставляются с TIME
  • Instant , LocalDateTime , OffsetDateTime и ZonedDateTime сопоставляются с TIMESTAMP

Это означает, что мы можем пометить эти поля только аннотацией @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. Заключение

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

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