Получение даты из ResultSet для использования с классами java.time

Есть ли способ получить java.time (новое в Java 8) совместимый временной класс из ResultSet?

Я знаю, что вы можете использовать ResultSet getDate или getTimestamp, но этот метод возвращает объекты java.sql.Date / java.sql.Timestamp, которые теперь устарели, поэтому использование их для создания ZonedDateTime или подобных им кажется плохой практикой.


person Thomas Paulin    schedule 21.04.2015    source источник
comment
java.sql.Date и т. д. официально НЕ являются устаревшими (не установлены устаревшие теги javadoc или аннотации). Что касается вашего вопроса, найдите JDBC 4.2 - поддержка вашей базы данных (фактически недоступна в большинстве случаев?) И используйте существующие методы setObject() и getObject()   -  person Meno Hochschild    schedule 21.04.2015


Ответы (3)


Большинство поставщиков баз данных пока не поддерживают JDBC 4.2. В этой спецификации говорится, что новые java.time-типы, такие как LocalDate будут / должны поддерживаться с использованием существующих методов setObject(...) и getObject(). Никакого явного преобразования не требуется и не предлагается (без изменения API).

Обходным путем для отсутствующей поддержки может быть ручное преобразование, как описано в Список рассылки Derby.

Что-то типа:

LocalDate birthDate = resultSet.getDate("birth_date").toLocalDate();

Как видите, в этих преобразованиях используются нерекомендуемые типы java.sql.Date и т. Д., См. Также javadoc.

person Meno Hochschild    schedule 21.04.2015
comment
Есть ли шанс, что дата переместится на следующий или предыдущий день с преобразованием в LocalDate? Я действительно не хочу, чтобы мой день рождения сдвигался из-за проблем с часовым поясом. - person Gert-Jan; 19.12.2016
comment
@ Gert-Jan Преобразования toLocalDate() и т. Д. Просто делегируются устаревшим методам, таким как date.getYear(), с использованием полуночи в местном часовом поясе (как требуется и указано для JDBC), см. Исходный код. Если вы попробуете НЕДЕЙСТВИТЕЛЬНОЕ местное время, которое не существует из-за изменения dst, вы, вероятно, заметите какой-то странный скачок времени вперед (в основном это касается типов TIME и TIMESTAMP). В противном случае преобразование должно быть безопасным, если у вас есть JDBC-драйвер, который строго соблюдает спецификацию, а именно интерпретирует преобразование в локальном tz. - person Meno Hochschild; 19.12.2016
comment
Хм ... в полночь? Что, если на свидании в этот день нет полуночи? - person Trejkaz; 30.06.2017
comment
@Trejkaz Если полночь не существует из-за разницы между стандартным и летним временем, время обычно увеличивается на величину разрыва. Это стандартное поведение как в старой Java, так и в новых java.time-классах. Например: America / Sao_Paolo не увидит полуночи 15 октября этого года, поэтому самое раннее местное время в этот день будет 1:00. - person Meno Hochschild; 30.06.2017
comment
На самом деле java.time решает проблему полностью, вызывая метод atStartOfDay, поэтому нет никаких сомнений в том, что он делает, тогда как формулировка, включающая полночь, всегда заставляет меня задуматься. - person Trejkaz; 30.06.2017
comment
@Trejkaz См. Также javadoc. Однако точные детали реализации перехода «зима-лето» не подлежат настройке (когда-то планировались, но затем были исключены во время разработки JSR-310). - person Meno Hochschild; 30.06.2017

Новые методы на Timestamp

Java 8 включает новые методы в классе java.sql.Timestamp для преобразования в объекты java.time и обратно. Эти удобные методы - временная мера, пока драйверы JDBC не будут обновлены для новых типов данных.

То же для Date и Time

Классы java.sql.Date и java.sql.Time имеют схожие java-классы. методы преобразования времени также добавлены в Java 8.

person Basil Bourque    schedule 21.04.2015

Сегодня большинство из нас используют драйверы, совместимые с JDBC 4.2, что немного улучшает ситуацию по сравнению с ответами 2015 года.

Чтобы получить LocalDate из набора результатов:

    LocalDate dateFromDatabase = yourResultSet.getObject(yourColumnIndex, LocalDate.class);

or

    LocalDate dateFromDatabase = yourResultSet.getObject("yourColumnLabel", LocalDate.class);

В ResultSet не было добавлено никаких новых методов, чтобы это работало. Метод getObject был там все время. Новое в том, что начиная с JDBC 4.2 он принимает LocalDate.class в качестве второго аргумента и возвращает LocalDate. Вышеупомянутое работает, когда запрос возвращает столбец с типом данных SQL date (на самом деле учитывается тип JDBC, но они склонны соглашаться).

Вы также можете передавать классы других типов java.time. И получите обратно соответствующий тип. Например:

    OffsetDateTime dateTimeFromDatabase
            = yourResultSet.getObject(yourTimestampWithTimeZoneColumnIndex, OffsetDateTime.class);

Используемые типы java.time:

SQL datatype            | java.time type
------------------------+-----------------------------------------------------------
date                    | LocalDate
time                    | LocalTime
timestamp               | LocalDateTime
timestamp with timezone | Officially OffsetDateTime; many drivers accept Instant too
time with timezone      | OffsetTime

Для передачи другим путем, из Java в вашу базу данных (для использования в качестве параметров запроса или для хранения) PreparedStatement.setObject теперь также принимает объекты указанных выше типов java.time. Поскольку вы передаете объект типа, при использовании этого пути нет необходимости в отдельном параметре типа.

person Ole V.V.    schedule 27.02.2019