Hibernate –日付と時刻のマッピング
1. 前書き
この記事では、java.sql、java.util、java.timeパッケージのクラスを含め、Hibernateで時間列の値をマッピングする方法を示します。
2. プロジェクトのセットアップ
時間タイプのマッピングを示すために、H2データベースと最新バージョンのhibernate-coreライブラリが必要になります。
org.hibernate
hibernate-core
5.2.12.Final
com.h2database
h2
1.4.194
hibernate-coreライブラリの現在のバージョンについては、Maven Centralリポジトリにアクセスしてください。
3. タイムゾーンの設定
When dealing with dates, it’s a good idea to set a specific time zone for the JDBC driver.このようにして、アプリケーションはシステムの現在のタイムゾーンから独立します。
この例では、セッションごとに設定します。
session = HibernateUtil.getSessionFactory().withOptions()
.jdbcTimeZone(TimeZone.getTimeZone("UTC"))
.openSession();
別の方法は、セッションファクトリの構築に使用されるHibernateプロパティファイルにhibernate.jdbc.time_zoneプロパティを設定することです。 このようにして、アプリケーション全体に対してタイムゾーンを1回指定できます。
4. java.sqlタイプのマッピング
java.sqlパッケージには、SQL標準で定義されているタイプに合わせたJDBCタイプが含まれています。
-
Dateは、DATE SQLタイプに対応します。これは、時刻のない日付のみです。
-
Timeは、TIME SQLタイプに対応します。これは、時間、分、秒で指定された時刻です。
-
Timestampには、最大ナノ秒の精度で日付と時刻に関する情報が含まれ、TIMESTAMPSQLタイプに対応します。
これらの型は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タイプ
The type java.util.Date contains both date and time information, up to millisecond precision.ただし、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タイプに応じて、DATE、TIME、またはTIMESTAMPのいずれかになります。マッピングに使用します。
次に、対応するフィールドを次のように設定できます。
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"));
これまで見てきたように、the java.util.Date type (milliseconds precision) is not precise enough to handle the Timestamp value (nanoseconds precision).
したがって、データベースからエンティティを取得すると、最初にjava.util.Dateを永続化した場合でも、当然のことながら、このフィールドにjava.sql.Timestampインスタンスが見つかります。
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タイプのマッピング
Since Java 8, the new Java Date and Time API is available for dealing with temporal values。 この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パッケージのすべての時間クラスには、適切な形式を使用して提供されたString値を解析するための静的なparse()メソッドがあります。 したがって、エンティティフィールドの値を設定する方法は次のとおりです。
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でさまざまなタイプの一時的な値をマップする方法を示しました。
記事のソースコードはover on GitHubで入手できます。