«1. Обзор

Версия JPA 2.2 официально представила поддержку Java 8 Date and Time API. До этого либо приходилось полагаться на проприетарное решение, либо приходилось использовать JPA Converter API.

В этом руководстве мы покажем, как отображать различные типы даты и времени Java 8. Особое внимание мы уделим тем, которые учитывают информацию о смещении.

2. Зависимости Maven

Прежде чем мы начнем, нам нужно включить JPA 2.2 API в путь к классам проекта. В проекте на основе Maven мы можем просто добавить его зависимость в наш файл pom.xml:

<dependency>
    <groupId>javax.persistence</groupId>
    <artifactId>javax.persistence-api</artifactId>
    <version>2.2</version>
</dependency>

Кроме того, для запуска проекта нам нужна реализация JPA и драйвер JDBC базы данных, с которой мы будем работать. с участием. В этом руководстве мы будем использовать EclipseLink и базу данных PostgreSQL:

<dependency>
    <groupId>org.eclipse.persistence</groupId>
    <artifactId>eclipselink</artifactId>
    <version>2.7.4</version>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>org.postgresql</groupId>
    <artifactId>postgresql</artifactId>
    <version>42.2.5</version>
    <scope>runtime</scope>
    <type>bundle</type>
</dependency>

Не стесняйтесь проверять последние версии JPA API, EclipseLink и драйвера JDBC PostgreSQL на Maven Central.

Конечно, мы можем использовать другие базы данных или реализации JPA, такие как Hibernate.

3. Поддержка TimeZone

Мы можем работать с любой базой данных, но сначала мы должны проверить поддержку этих стандартных типов SQL, поскольку JDBC 4.2 основан на:

    TIMESTAMP(n) WITH TIME ZONE TIMESTAMP (n) БЕЗ ЧАСОВОГО ПОЯСА TIME(n) С ЧАСОВЫМ ПОЯСОМ TIME(n) БЕЗ ЧАСОВОГО ПОЯСА

Здесь n — точность в долях секунды и может быть от 0 до 9 цифр. БЕЗ ЧАСОВОГО ПОЯСА является необязательным и может быть опущен. Если указано WITH TIME ZONE, требуется имя часового пояса или смещение относительно UTC.

Мы можем представить часовой пояс в одном из следующих двух форматов:

    Название часового пояса Смещение от UTC или буква Z для UTC

Для нашего примера мы выбрали базу данных PostgreSQL благодаря ее полной поддержке Введите SQL ВРЕМЯ С ЧАСОВЫМ ПОЯСОМ.

Обратите внимание, что другие базы данных могут не поддерживать эти типы.

4. Сопоставление типов даты до Java 8

До Java 8 нам обычно приходилось сопоставлять общие типы SQL TIME, DATE и TIMESTAMP либо с классами java.sql.* java.sql.Time, java .sql.Date и java.sql.Timestamp соответственно или к типам java.util java.util.Date и java.util.Calendar.

Во-первых, давайте посмотрим, как использовать типы java.sql. Здесь мы просто определяем атрибуты с типами java.sql как часть класса @Entity:

@Entity
public class JPA22DateTimeEntity {

    private java.sql.Time sqlTime;
    private java.sql.Date sqlDate;
    private java.sql.Timestamp sqlTimestamp;
    
    // ...
}

Хотя типы java.sql работают как любые другие типы без дополнительного сопоставления, типы java.util требуют для указания соответствующих временных типов.

Это делается с помощью аннотации @Temporal, атрибут value которой позволяет указать соответствующий тип JDBC, используя перечисление TemporalType:

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

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

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

Обратите внимание, что если мы используем Hibernate в качестве реализации, это не поддержка сопоставления календаря со временем.

Точно так же мы можем использовать класс Calendar:

@Temporal(TemporalType.TIME)
private Calendar calendarTime;

@Temporal(TemporalType.DATE)
private Calendar calendarDate;

@Temporal(TemporalType.TIMESTAMP)
private Calendar calendarTimestamp;

Ни один из этих типов не поддерживает часовой пояс или смещение. Чтобы иметь дело с этими фрагментами информации, нам традиционно приходилось хранить время в формате UTC.

5. Сопоставление типов даты Java 8

В Java 8 представлены пакеты java.time, а в API JDBC 4.2 добавлена ​​поддержка дополнительных типов SQL TIMESTAMP WITH TIME ZONE и TIME WITH TIME ZONE.

Теперь мы можем сопоставить типы JDBC TIME, DATE и TIMESTAMP с типами java.time — LocalTime, LocalDate и LocalDateTime:

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

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

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

Кроме того, у нас есть поддержка смещения местного часового пояса относительно UTC. через классы OffsetTime и OffsetDateTime:

@Column(name = "offset_time", columnDefinition = "TIME WITH TIME ZONE")
private OffsetTime offsetTime;

@Column(name = "offset_date_time", columnDefinition = "TIMESTAMP WITH TIME ZONE")
private OffsetDateTime offsetDateTime;

Соответствующие сопоставленные типы столбцов должны быть TIME WITH TIME ZONE и TIMESTAMP WITH TIME ZONE. К сожалению, не все базы данных поддерживают эти два типа.

Как мы видим, JPA поддерживает эти пять классов в качестве основных типов, и нет необходимости в дополнительной информации, чтобы различать информацию о дате и/или времени.

После сохранения нового экземпляра нашего класса сущностей мы можем проверить правильность вставки данных:

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

До появления Java 8 и JPA 2.2 разработчикам обычно приходилось преобразовывать типы даты/времени в формат UTC. перед их сохранением. JPA 2.2 теперь поддерживает эту функцию «из коробки», поддерживая смещение относительно UTC и используя поддержку JDBC 4.2 для часового пояса.

«Полный исходный код этих примеров можно найти на Github.