Java >> Java チュートリアル >  >> Tag >> Jdbc

Java 8 で JDBC の日付処理を修正する機会を逃しましたか?

データベースで日付 2015-09-13 を表すには、タイムゾーンを選択する必要があり、そのタイムゾーンの文字列 "2015-09-13T00:00:00.000" を java.util.Date として解析してミリ秒を取得します。 JDBC ドライバーが日付 2015-09 を正しく再計算できるように、選択されたタイムゾーンを保持する Calendar を渡します。このミリ秒値から -13

なんで?電話するだけ

Date.valueOf("2015-09-13"); // From String
Date.valueOf(localDate);    // From java.time.LocalDate

動作はすべての JDBC ドライバーで正しいものになります:タイムゾーンなしのローカル日付。逆の操作は次のとおりです:

date.toString();    // To String
date.toLocalDate(); // To java.time.LocalDate

java.sql.Date に頼るべきではありません の java.util.Date への依存 、そしてそれが java.time.Instant のセマンティクスを継承しているという事実 Date(long)経由 または Date.getTime()

では、下位互換性を維持しながら JDBC の混乱を一掃する大きな機会を逃したのではないでしょうか? [...]

場合によります。 JDBC 4.2 仕様では、LocalDate をバインドできることが指定されています setObject(int, localDate) 経由で入力 、および LocalDate をフェッチする getObject(int, LocalDate.class) で入力 、ドライバーがその準備ができている場合。フォーマルな default ほどエレガントではない もちろん、あなたが提案した方法です。


簡単な答え:いいえ。Java 8 の日付と時刻の型がサポートされているため、Java 8 / JDBC 4.2 では日時の処理が修正されています。これはデフォルトの方法ではエミュレートできません。

Java 8 では、これらのデフォルト メソッドを PreparedStatement と ResultSet に追加するだけで済みます。

これはいくつかの理由で不可能です:

  • java.time.OffsetDateTime java.sql には同等のものはありません
  • java.time.LocalDateTime java.sql.Timestamp を介して変換するときに、DST トランジションで中断します 後者は JVM タイム ゾーンに依存するため、以下のコードを参照してください
  • java.sql.Time ミリ秒の解像度がありますが、java.time.LocalTime ナノ秒の解像度

したがって、適切なドライバーのサポートが必要です。デフォルトのメソッドは java.sql を介して変換する必要があります。 データ損失を引き起こすタイプ。

このコードを夏時間のある JVM タイム ゾーンで実行すると、コードが壊れます。クロックが「進む」次のトランジションを検索し、LocalDateTime を選択します。 つまり、移行の真っ最中です。 Java LocalDateTime であるため、これは完全に有効です。 または SQL TIMESTAMP タイム ゾーンがないため、タイム ゾーン ルールがなく、したがって夏時間もありません。 java.sql.Timestamp 一方、JVM タイム ゾーンにバインドされているため、夏時間の対象となります。

ZoneId systemTimezone = ZoneId.systemDefault();
Instant now = Instant.now();

ZoneRules rules = systemTimezone.getRules();
ZoneOffsetTransition transition = rules.nextTransition(now);
assertNotNull(transition);
if (!transition.getDateTimeBefore().isBefore(transition.getDateTimeAfter())) {
  transition = rules.nextTransition(transition.getInstant().plusSeconds(1L));
  assertNotNull(transition);
}

Duration gap = Duration.between(transition.getDateTimeBefore(), transition.getDateTimeAfter());
LocalDateTime betweenTransitions = transition.getDateTimeBefore().plus(gap.dividedBy(2L));

Timestamp timestamp = java.sql.Timestamp.valueOf(betweenTransitions);
assertEquals(betweenTransitions, timestamp.toLocalDateTime());

Java タグ