2016-06-12 14 views
3

LocalDateDATEの列に格納し、そのまま取得します。 DATELocalDateは両方とも定義によって「ローカル」タイプです。したがって、タイムゾーンのコンセプトは、決して干渉してはなりません。DATEをLocalDateにマップする方法

以下のコードは、インメモリデータベースにDATE列のテーブルを作成する最小限の例です。 Mavenアーティファクトcom.h2database:h2:1.4.192はクラスパス内になければなりません。

まず、方法insertretrieve定義:insert方法は、単一引用符でLocalDatetoString値を使用すること

static void insert(DataSource ds, String date) throws SQLException { 
    try (Connection conn = ds.getConnection(); 
     Statement stmt = conn.createStatement()) { 
    stmt.execute("CREATE TABLE people (id BIGINT NOT NULL AUTO_INCREMENT" 
     + ", born DATE NOT NULL, PRIMARY KEY (id));"); 
    stmt.execute("INSERT INTO people (born) VALUES ('" + date + "')"); 
    } 
} 

static LocalDate retrieve(DataSource ds) throws SQLException { 
    try (Connection conn = ds.getConnection(); 
     Statement stmt = conn.createStatement(); 
     ResultSet rs = stmt.executeQuery("SELECT * FROM people limit 1")) { 
    if (rs.next()) { 
     java.sql.Date retrieved = java.sql.Date.valueOf(rs.getString("born")); 
     return retrieved.toLocalDate(); 
    } 
    throw new IllegalStateException("No data"); 
    } 
} 

お知らせするので、Java™は、タイムゾーンのあいまいさを作成するための機会はありません。そして、次が印刷され

public static void main(String[] args) throws Exception { 
    DataSource ds = JdbcConnectionPool.create("jdbc:h2:mem:test", "sa", "sa"); 
    LocalDate born = LocalDate.parse("2015-05-20"); 
    insert(ds, born.toString()); 
    System.out.println("Inserted: " + born); 
    for (int i : new int[]{-14, 0, 12}) { 
    TimeZone z = TimeZone.getTimeZone(String.format("Etc/GMT%+02d", i)); 
    TimeZone.setDefault(z); 
    System.out.println("Retrieved: " + retrieve(ds)); 
    } 
} 

 
Inserted: 2015-05-20 
Retrieved: 2015-05-20 
Retrieved: 2015-05-19 
Retrieved: 2015-05-18 

それは同じ値を返すようにretrieveメソッドを記述するためにどのように今insert一度、その後、別のtimzone設定で数回retrieve、毎回呼び出しますそれは無条件に、データベーステーブルが変更されないと仮定して挿入されましたか?

+0

あなたはjava.util.Dateをインポートする:ユーザーTunakiにより示唆されるように

static LocalDate retrieve(DataSource ds) throws SQLException { try (Connection conn = ds.getConnection(); Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery("SELECT * FROM people limit 1")) { if (rs.next()) { ZoneId utc = ZoneId.of("UTC"); TimeZone z = TimeZone.getTimeZone(utc); Calendar cal = Calendar.getInstance(z); java.sql.Date retrieved = rs.getDate("born", cal); long time = retrieved.getTime(); java.util.Date utilDate = new java.util.Date(time); Instant instant = utilDate.toInstant(); ZonedDateTime zdt = instant.atZone(utc); return zdt.toLocalDate(); } } throw new IllegalStateException("No data"); } 

java.util.Dateを介した変換は、この質問に概説されていますか?その 'retrieved ='行では、割り当ての左側では完全修飾された 'java.sql.Date'を使用しますが、右側では使用しません。 –

+1

3つの同じ「LocalDate」が印刷されることを期待していたのはなぜですか?あなたは '2015-05-20'の日付を挿入しています。次に、デフォルトのタイムゾーンを変更すると、 'java.sql.Date.toLocalDate'メソッドは別の結果を返します。 – Tunaki

+0

@BasilBourque fixed –

答えて

3

私はちょうどあなたのretrieveメソッドに次の変更をしようと、それは私の仕事:

H2 documentation for the DATE Typeは、それが

日付データ型であることを述べています。形式はyyyy-MM-ddです。

だから、代わりにあなたの...

java.sql.Date retrieved = (java.sql.Date) rs.getObject("born"); 
return retrieved.toLocalDate(); 

の...私はちょうど...

return LocalDate.parse(rs.getString("born")); 

を使用...そして私のコードは

Inserted: 2015-05-20 
Retrieved: 2015-05-20 
Retrieved: 2015-05-20 
Retrieved: 2015-05-20 
+0

nullの扱いを除いて、私は安全に見えます。ありがとう!私はまだH2の代わりにOracle DBを使用する方法を考えています(これは 'DATE'の秒精度を格納します)。しかし、それは別の質問でしょう。 –

1
を作成しました

以下の解決策も機能します。私は受け入れられた答えでString経由の変換を好んでいます。なぜなら、以下に示すタイムゾーンの調整を避けるからです。ただし、すべてのデータベースで同じように動作するわけではありません。オラクルは、DATEの異なる定義を持っています。 Missed opportunity to fix JDBC date handling in Java 8?

関連する問題