1. 概要
JPA 2.2バージョンでは、 Java 8 Date and TimeAPIのサポートが正式に導入されました。 その前は、独自のソリューションに依存するか、JPAConverterAPIを使用する必要がありました。
このチュートリアルでは、さまざまなJava8の日付と時刻のタイプをマップする方法を示します。 特に、オフセット情報を考慮したものに焦点を当てます。
2. Mavenの依存関係
開始する前に、JPA2.2APIをプロジェクトのクラスパスに含める必要があります。 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>
MavenCentralでJPAAPI 、 EclipseLink 、およびPostgreSQLJDBCドライバーの最新バージョンを確認してください。
もちろん、他のデータベースやHibernateのようなJPA実装を使用することもできます。
3. TimeZoneサポート
任意のデータベースで作業できますが、JDBC 4.2は以下に基づいているため、最初に、これらの標準SQLタイプのサポートを確認する必要があります。
- タイムスタンプ付きタイムスタンプ(n)
- タイムスタンプなしのタイムスタンプ(n)
- タイムゾーン付きのTIME(n)
- タイムゾーンなしのTIME(n)
ここで、 n は秒の小数部の精度であり、0〜9桁です。 WITHOUT TIME ZONE はオプションであり、省略できます。 WITH TIME ZONE を指定する場合は、タイムゾーン名またはUTCへのオフセットが必要です。
タイムゾーンは、次の2つの形式のいずれかで表すことができます。
- タイムゾーン名
- UTCからのオフセットまたはUTCの文字Z
この例では、SQLタイプ TIME WITH TIME ZONE を完全にサポートしているため、PostgreSQLデータベースを選択しました。
他のデータベースはこれらのタイプをサポートしていない可能性があることに注意してください。
4. Java8より前の日付タイプのマッピング
Java 8より前は、通常、汎用SQLタイプ TIME、DATE 、およびTIMESTAMPをjava.sql。*クラスのいずれかにマップする必要がありました。 java.sql.Time 、 java.sql.Date、、 java.sql.Timestamp、、またはjava.utilタイプ[X272X ]java.util.Dateおよびjava.util.Calendar。
まず、 java.sqlタイプの使用方法を見てみましょう。 ここでは、@Entityクラスの一部としてjava.sqlタイプで属性を定義しているだけです。
@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 属性により、 TemporalType 列挙を使用して、対応するJDBCタイプを指定できます。
@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. Java8の日付タイプのマッピング
Java8ではjava.timeパッケージが導入され、JDBC 4.2 APIでは、追加のSQLタイプ TIMESTAMP WITH TIMEZONEおよびTIMEWITH TIMEZONEのサポートが追加されました。
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;
さらに、ResetTimeおよびOffsetDateTimeクラスを介してUTCへのオフセットローカルタイムゾーンをサポートしています。
@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 TIMEZONEおよびTIMESTAMPWITH TIMEZONEである必要があります。 残念ながら、すべてのデータベースがこれら2つのタイプをサポートしているわけではありません。
ご覧のとおり、JPAはこれらの5つのクラスを基本タイプとしてサポートしており、日付や時刻の情報を区別するために追加の情報は必要ありません。
エンティティクラスの新しいインスタンスを保存した後、データが正しく挿入されていることを確認できます。
6. 結論
Java8およびJPA2.2より前では、開発者は通常、日付/時刻タイプを永続化する前にUTCに変換する必要がありました。 JPA 2.2は、UTCへのオフセットをサポートし、タイムゾーンのJDBC 4.2サポートを活用することにより、この機能をすぐにサポートするようになりました。
これらのサンプルの完全なソースコードは、Githubのにあります。