如何将sql DATE映射到LocalDate
我想将一个LocalDate
存储在DATE
列中并保持不变。 根据定义, DATE
和LocalDate
都是“本地”类型。 因此, 时区的概念不应以任何方式干涉。
下面的代码是一个最小的示例,它在内存数据库中创建一个带有DATE
列的表。 maven artifact 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
方法在单引号中使用LocalDate
的toString
值,因此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)); } }
然后打印以下内容:
已插入:2015-05-20 检索:2015-05-20 检索:2015-05-19 检索: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.util.Date
的转换: 错过了在Java 8中修复JDBC日期处理的机会?