[英]How to map sql DATE to LocalDate
I want to store a LocalDate
in a DATE
column and retrieve it unchanged. 我想将LocalDate
存储在DATE
列中并保持不变。 Both DATE
and LocalDate
are "local" types by definition. 根据定义, DATE
和LocalDate
均为“本地”类型。 Therefore, the concept of timezone should not interfere in any way. 因此, 时区的概念不应以任何方式干涉。
The code below is a minimal example that creates a table with a DATE
column in a in-memory database. 下面的代码是一个最小示例,该示例在内存数据库中创建一个带有DATE
列的表。 The maven artifact com.h2database:h2:1.4.192
must be in the classpath. Maven工件com.h2database:h2:1.4.192
必须在类路径中。
First, define methods insert
and retrieve
: 首先,定义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");
}
}
Notice that the insert
method uses the toString
value of the LocalDate
in single quotes, so there's no opportunity for Java™ to create timezone ambiguity. 注意, insert
方法在单引号中使用LocalDate
的toString
值,因此Java™没有机会创建时区歧义。 Now call insert
once and then several times retrieve
, with different timzone settings each time: 现在打电话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));
}
}
Then the following is printed: 然后打印以下内容:
Inserted: 2015-05-20 Retrieved: 2015-05-20 Retrieved: 2015-05-19 Retrieved: 2015-05-18
How to write the retrieve
method so that it returns the same value that was inserted unconditionally , assuming that the database table doesn't change? 假设数据库表不变,如何编写retrieve
方法,使其返回无条件插入的相同值?
I just tried the following modification to your retrieve
method and it worked for me: 我只是尝试对您的retrieve
方法进行以下修改,但对我有用:
The H2 documentation for the DATE Type says that it is DATE类型的H2文档说它是
The date data type. 日期数据类型。 The format is yyyy-MM-dd. 格式为yyyy-MM-dd。
So, instead of your ... 所以,而不是你的...
java.sql.Date retrieved = (java.sql.Date) rs.getObject("born");
return retrieved.toLocalDate();
... I just used ... 我刚用过
return LocalDate.parse(rs.getString("born"));
... and my code produced ...和我的代码产生
Inserted: 2015-05-20
Retrieved: 2015-05-20
Retrieved: 2015-05-20
Retrieved: 2015-05-20
The following solution also works. 以下解决方案也适用。 I prefer the conversion via String
in the accepted answer, because it avoids the timezone tinkering shown below. 我更喜欢在接受的答案中通过String
进行转换,因为它避免了如下所示的时区调整。 It may however not work the same way on all databases because some, eg Oracle, have a different definition of DATE
. 但是,它可能无法在所有数据库上以相同的方式工作,因为某些数据库(例如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");
}
The conversion via java.util.Date
is outlined in this question, as suggested by user Tunaki: Missed opportunity to fix JDBC date handling in Java 8? 正如用户Tunaki所建议的那样,此问题概述了通过java.util.Date
的转换:是否缺少在Java 8中修复JDBC日期处理的机会?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.