35

Is there anyway to get a java.time (new in Java 8) compatible time class out of a ResultSet?

I am aware you can use ResultSet's getDate or getTimestamp but these method return java.sql.Date / java.sql.Timestamp objects which are now deprecated so it seems like bad practice to use them in order to create a ZonedDateTime or similar.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
Thomas Paulin
  • 515
  • 1
  • 6
  • 12
  • 3
    java.sql.Date etc. are officially NOT deprecated (no deprecated-javadoc-tag or annotation is set). About your question, look for JDBC 4.2 - support of your db (actually not available in most cases?) and use then existing methods `setObject()` and `getObject()` – Meno Hochschild Apr 21 '15 at 13:49

3 Answers3

31

Most database vendors don't support JDBC 4.2 yet. This specification says that the new java.time-types like LocalDate will/should be supported using the existing methods setObject(...) and getObject(). No explicit conversion is required and offered (no API-change).

A workaround for the missing support can be manual conversion as described on the Derby-mailing list.

Something like:

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

As you can see, these conversions use the non-deprecated types java.sql.Date etc., see also the javadoc.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
Meno Hochschild
  • 42,708
  • 7
  • 104
  • 126
  • Is there any chance that the date will flip to the next or previous day with the conversion to LocalDate? I really don't want my birthday shifting as a result of timezone issues. – Gert-Jan Dec 19 '16 at 14:19
  • 1
    @Gert-Jan The conversions `toLocalDate()` etc. just delegate to deprecated methods like `date.getYear()` using midnight in the local timezone (as required and specified for JDBC), see source code. If you try an INVALID local time which does not exist due to dst change then you will probably observe some strange time jump forward (mainly concerns the TIME- and TIMESTAMP-types). Otherwise the conversion should be safe as long as you have a JDBC-driver which respects the specification closely, namely to interprete the conversion in local tz. – Meno Hochschild Dec 19 '16 at 14:39
  • Hmm... using midnight? What if the date doesn't have a midnight on that day? – Hakanai Jun 30 '17 at 01:56
  • @Trejkaz If midnight does not exist due to a gap between standard and summer time then the time will usually jump forward by the size of the gap. This is the standard behaviour in old Java as well as in new `java.time`-classes. For example: America/Sao_Paolo will not see midnight on 15th of October this year hence the earliest local time on that day will be 1AM. – Meno Hochschild Jun 30 '17 at 08:08
  • Actually, `java.time` side-steps the issue entirely by calling the method `atStartOfDay`, so there is no question about what it does, whereas wording including "midnight" always makes me wonder. – Hakanai Jun 30 '17 at 14:58
  • @Trejkaz See also the [javadoc](http://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html#atStartOfDay-java.time.ZoneId-). The exact details how to realize the winter-summer-transition is not configurable however (was once planned but then thrown out during development of JSR-310). – Meno Hochschild Jun 30 '17 at 15:42
27

Today most of us are using JDBC 4.2 compliant drivers, which improves the situation quite a bit compared to the answers from 2015.

To get a LocalDate from your result set:

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

or

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

No new method has been added to ResultSet for this to work. The getObject method was there all the time. The new thing is that since JDBC 4.2 it accepts LocalDate.class as the second argument and returns a LocalDate. The above works when the query returns a column with SQL datatype date (really the JDBC type counts, but they tend to agree).

You can pass classes of other java.time types too. And get the corresponding type back. For example:

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

The java.time types to use are:

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

For passing the other way, from Java to your database (for use as query parameters or for storing) PreparedStatement.setObject now accepts objects of the above java.time types too. Since you are passing an object of a type, there is no need for a separate type parameter when going this way.

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
25

New Methods On Timestamp

Java 8 includes new methods on the java.sql.Timestamp class to convert to and from java.time objects. These convenience methods are a stop-gap measure until JDBC drivers can be updated for the new data types.

Ditto For Date & Time

The java.sql.Date and java.sql.Time classes have similar java.time conversion methods added in Java 8 as well.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154