1. Обзор
Версия JPA 2.2 официально представила поддержку Java 8 Date
and Time
API . До этого либо приходилось полагаться на проприетарное решение, либо приходилось использовать JPA Converter API.
В этом руководстве мы покажем, как сопоставлять различные типы даты
и времени
Java 8 . Особое внимание мы уделим тем, которые учитывают информацию о смещении.
2. Зависимости Maven
Прежде чем мы начнем, нам нужно включить API JPA 2.2 в путь к классам проекта. В проекте на основе 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. Поддержка часового пояса
Мы можем работать с любой базой данных, но сначала мы должны проверить поддержку этих стандартных типов SQL, поскольку JDBC 4.2 основан на:
TIMESTAMP(n) С ЧАСОВЫМ ПОЯСОМ
TIMESTAMP(n) БЕЗ ЧАСОВОГО ПОЯСА
ВРЕМЯ(n) С ЧАСОВЫМ ПОЯСОМ
ВРЕМЯ(n) БЕЗ ЧАСОВОГО ПОЯСА
Здесь n
— точность в долях секунды и находится в диапазоне от 0 до 9 цифр. БЕЗ ЧАСОВОГО ПОЯСА
является необязательным и может быть опущен. Если указано WITH TIME ZONE
, требуется имя часового пояса или смещение относительно UTC.
Мы можем представить часовой пояс в одном из этих двух форматов:
- Название часового пояса
- Смещение от UTC или буква Z для UTC
Для нашего примера мы выбрали базу данных PostgreSQL благодаря полной поддержке типа SQL TIME WITH TIME ZONE
.
Обратите внимание, что другие базы данных могут не поддерживать эти типы.
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
с TIME
.
Точно так же мы можем использовать класс 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 .