簡體   English   中英

如何將SQL DATE映射到LocalDate

[英]How to map sql DATE to LocalDate

我想將LocalDate存儲在DATE列中並保持不變。 根據定義, DATELocalDate均為“本地”類型。 因此, 時區的概念不應以任何方式干涉。

下面的代碼是一個最小示例,該示例在內存數據庫中創建一個帶有DATE列的表。 Maven工件com.h2database:h2:1.4.192必須在類路徑中。

首先,定義insertretrieve方法:

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方法在單引號中使用LocalDatetoString值,因此Java™沒有機會創建時區歧義。 現在打電話insert一次,然后多次retrieve ,每次用不同的timzone設置:

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方法,使其返回無條件插入的相同值?

我只是嘗試對您的retrieve方法進行以下修改,但對我有用:

DATE類型H2文檔說它是

日期數據類型。 格式為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

以下解決方案也適用。 我更喜歡在接受的答案中通過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");
}

正如用戶Tunaki所建議的那樣,此問題概述了通過java.util.Date的轉換:是否缺少在Java 8中修復JDBC日期處理的機會?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM