7

を列に格納し、変更せずに取得したいLocalDate。とはDATE両方とも、定義上「ローカル」タイプです。したがって、タイムゾーンの概念は決して干渉すべきではありません。DATELocalDate

以下のコードは、DATEメモリ内データベースに列を持つテーブルを作成する最小限の例です。Maven アーティファクトcom.h2database:h2:1.4.192はクラスパスにある必要があります。

まず、メソッドinsertとを定義しretrieveます。

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");
  }
}

insertこのメソッドは単一引用符で囲まれたtoString値を使用するLocalDateため、Java™ がタイムゾーンのあいまいさを作成する機会がないことに注意してください。ここで、毎回異なる timzone 設定で 1insert回と数回呼び出します。retrieve

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));
  }
}

次に、以下が出力されます。

挿入: 2015-05-20
取得日: 2015-05-20
取得日: 2015-05-19
取得日: 2015-05-18

データベーステーブルが変更されないと仮定して、無条件retrieveに挿入された同じ値を返すようにメソッドを記述する方法は?

4

2 に答える 2

1

次の解決策も機能します。String以下に示すタイムゾーンのいじくり回しを避けるため、受け入れられた回答での変換を好みます。ただし、一部のデータベース、たとえば Oracle では の定義が異なるため、すべてのデータベースで同じように機能するとは限りません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()) {
      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ユーザー Tunaki によって提案されているように、変換はこの質問で概説されています: Java 8 で JDBC 日付処理を修正する機会を逃しましたか?

于 2016-06-13T17:16:49.870 に答える