我正在尝试将新的java.time
类与最新版本的Sql Server JDBC驱动程序一起使用。在我阅读本文时,它应该只适用于PreparedStatement.setObject()
和ResultSet.getObject()
这些方法。
因此,我创建了示例代码,但无法使其与ResultSets一起使用。我不知道我在做什么错。
Connection connection = DriverManager.getConnection(connectionString);
PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM myTable WHERE ? BETWEEN date_from AND date_to");
preparedStatement.setObject(1, LocalDateTime.now()); // That works
ResultSet resultSet = preparedStatement.executeQuery();
if (resultSet.next()) {
Object o = resultSet.getObject("date_from");
o.getClass() returns java.sql.Timestamp
LocalDateTime dateTime = resultSet.getObject("date_from", LocalDateTime.class);
}
这引发异常:
com.microsoft.sqlserver.jdbc.SQLServerException:不支持转换为类java.time.LocalDateTime。
驱动程序版本:mssql-jdbc-6.5.4.jre8-preview.jar
SQL Server版本:2016
如何解释底部表格中的这句话:
Java 8中的新Java类: LocalDate / LocalTime / LocalDateTime, OffsetTime / OffsetDateTime
新的JDBC类型: TIME_WITH_TIMEZONE, TIMESTAMP_WITH_TIMEZONE, REF_CURSOR
REF_CURSOR is not supported in SQL Server. Driver throws a SQLFeatureNotSupportedException exception if this type is used. The driver supports all other new Java and JDBC type mappings as specified in the JDBC 4.2 specification.
答案 0 :(得分:2)
这是因为resultSet.getObject(...)
的Microsoft SQL Server JDBC驱动程序实现无法从java.sql.Timestamp
自动转换为LocalDateTime
。
作为一种解决方法,您可以获取值为java.sql.Timestamp
,然后使用以下方法将java.sql.Timestamp
转换为LocalDateTime
:java.sql.Timestamp.toLocalDateTime()
LocalDateTime dateTime = resultSet.getTimestamp("date_from").toLocalDateTime()
答案 1 :(得分:1)
我不知道我在做什么错。
您没有做错任何事情。 here报告说,您遇到了Microsoft JDBC驱动程序的缺陷。
因此,正如其他人所建议的,暂时需要检索时间戳并将其转换为LocalDateTime。但是,请注意,这种简单的解决方案
LocalDateTime dateTime = resultSet.getTimestamp("date_from").toLocalDateTime()
如果JVM的默认时区遵循夏令时,也就是“夏令时”,则将破坏某些日期/时间值。例如,
// time zone with Daylight Time
TimeZone.setDefault(TimeZone.getTimeZone("America/Edmonton"));
// test environment
Statement st = conn.createStatement();
st.execute("CREATE TABLE #tmp (id INT PRIMARY KEY, dt2 DATETIME2)");
st.execute("INSERT INTO #tmp (id, dt2) VALUES (1, '2018-03-11 02:00:00')");
ResultSet rs = st.executeQuery("SELECT dt2 FROM #tmp WHERE id=1");
rs.next();
// test code
LocalDateTime x = rs.getTimestamp("dt2").toLocalDateTime(); // bad
System.out.println(x.toString());
将打印“ 2018-03-11T03:00”。请注意,时间是“ 03:00”,而不是“ 02:00”。
相反,您需要将时间戳记提取为UTC,然后将其转换为UTC的LocalDateTime,从而删除时区分量
// time zone with Daylight Time
TimeZone.setDefault(TimeZone.getTimeZone("America/Edmonton"));
// test environment
Statement st = conn.createStatement();
st.execute("CREATE TABLE #tmp (id INT PRIMARY KEY, dt2 DATETIME2)");
st.execute("INSERT INTO #tmp (id, dt2) VALUES (1, '2018-03-11 02:00:00')");
ResultSet rs = st.executeQuery("SELECT dt2 FROM #tmp WHERE id=1");
rs.next();
// test code
Timestamp ts = getTimestamp("dt2", Calendar.getInstance(TimeZone.getTimeZone("UTC")));
LocalDateTime x = LocalDateTime.ofInstant(ts.toInstant(), ZoneId.of("UTC")); // good
System.out.println(x.toString());
其中显示“ 2018-03-11T02:00”。
答案 2 :(得分:0)
mssql-jdbc驱动程序似乎没有完全实现JDBC 4.2中指定的java.time支持。 ResultSet.getObject
不支持它,但是PreparedStatement.setObject
不支持它。
根据Loc Le的答案建议,解决方法是以Timestamp
的身份检索并将其转换为LocalDateTime
。
答案 3 :(得分:0)
这是等效转换的简单示例。测试自己。
@Test
public void testingConversionTimestampAndLocalDateTime(){
Timestamp initialTimestamp = new Timestamp(System.currentTimeMillis());
LocalDateTime localDateTime = LocalDateTime.ofInstant(initialTimestamp.toInstant(), ZoneId.of("America/Sao_Paulo"));
ZoneOffset zoneOffset = ZoneId.of("America/Sao_Paulo").getRules().getOffset(localDateTime);
Timestamp timestamp = Timestamp.from(localDateTime.toInstant(zoneOffset));
Timestamp timestamp1 = Timestamp.valueOf(localDateTime);
assertEquals(initialTimestamp, timestamp);
assertEquals(initialTimestamp, timestamp1);
}