Eu estou tentando usar novas java.time
aulas com a versão mais recente do SQL Server driver JDBC. Como eu li ele deve apenas trabalhar com métodos: PreparedStatement.setObject()
e ResultSet.getObject()
.
Então, eu criei código de exemplo, e não pode obtê-lo trabalhar com ResultSets. Eu não sei o que estou fazendo de errado aqui.
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);
}
Isso gera uma exceção:
com.microsoft.sqlserver.jdbc.SQLServerException: A conversão para classe java.time.LocalDateTime não é suportado.
versão do driver: mssql-jdbc-6.5.4.jre8-preview.jar
SQL Server versão: 2016
Como interpretar esta frase na tabela em baixo:
Novas classes de Java em Java 8: LocalDate / localtime / LocalDateTime, OffsetTime / OffsetDateTime
Novos tipos de 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.
Eu não sei o que estou fazendo de errado aqui.
Você não está fazendo nada de errado. Deparou-se com uma deficiência no driver JDBC da Microsoft para o SQL Server antes da versão 7.1.0 , discutido aqui .
Se você estiver usando mssql-jdbc versão 7.1.0 ou mais recente, em seguida, você pode usar getObject(x, LocalDateTime.class)
como esperado.
Para versões MSSQL-jdbc anteriores a 7.1.0, como já foi sugerido, você vai precisar para recuperar um Timestamp
e convertê-lo em um LocalDateTime
. No entanto, estar ciente de que a solução simplista ...
LocalDateTime dateTime = resultSet.getTimestamp("date_from").toLocalDateTime()
... vai certos valores de data / hora corruptos se o fuso horário padrão para o JVM observa horário de verão, também conhecido como "Summer Time". Por exemplo,
// 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());
imprimirá "2018-03-11T03: 00". Note-se que o tempo é "3:00", e não "2:00".
Em vez disso, você vai precisar para recuperar o Timestamp
como UTC e depois convertê-lo em um LocalDateTime
de UTC, eliminando assim a componente de fuso horário
// 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());
que imprime "2018-03-11T02: 00".