I\'m getting a bit confused by the behaviour of the SQL DATE data type vs. that of java.sql.Date
. Take the following statement, for example:
PreparedStatement stmt = connection.prepareStatement(sql);
stmt.setObject(1, LocalDate.EPOCH); // The epoch year LocalDate, '1970-01-01'.
ResultSet rs = stmt.executeQuery();
rs.next();
// It doesnt matter where you live or your JVM’s time zone setting
// since a LocalDate doesn’t have or use time zone
System.out.println(rs.getObject(1, LocalDate.class));
I didn’t test, but unless there’s a bug in your JDBC driver, the output in all time zones is:
1970-01-01
LocalDate
is a date without time of day and without time zone. So there is no millisecond value to get and no time of day to be confused about. LocalDate
is part of java.time, the modern Java date and time API. JDBC 4.2 specifies that you can transfer java.time objects including LocalDate
to and from your SQL database through the methods setObject
and getObject
I use in the snippet (so not setDate
nor getDate
).
I think that virtually all of us are using JDBC 4.2 drivers by now.
java.sql.Date
is a hack trying (not very successfully) to disguise a java.util.Date
as a date without time of day. I recommend that you don’t use that class.
From the documentation:
To conform with the definition of SQL
DATE
, the millisecond values wrapped by ajava.sql.Date
instance must be 'normalized' by setting the hours, minutes, seconds, and milliseconds to zero in the particular time zone with which the instance is associated.
“Associated” may be vague. What this means, I believe, is that the millisecond value must denote the start of day in your JVM’s default time zone (Europe/Zurich in your case, I suppose). So when you create new java.sql.Date(0)
equal to GMT 1970-01-01 00:00:00, it’s really you creating an incorrect Date
object, since this time is 01:00:00 in your time zone. JDBC is ignoring the time of day (we might have expected an error message, but don’t get any). So SQL is getting and returning a date of 1970-01-01. JDBC correctly translates this back to a Date
containing CET 1970-01-01 00:00:00. Or a millisecond value of -3 600 000. Yes, it’s confusing. As I said, don’t use that class.
If you had been at a negative GMT offset (for example most time zones in the Americas), new java.sql.Date(0)
would have been interpreted as 1969-12-31, so this would have been the date you had passed to and got back from SQL.
To make matters worse, think what happens when the JVM’s time zone setting is changed. Any part of your program and any other program running in the same JVM may do this at any time. This typically causes all java.sql.Date
objects created before the change to become invalid and may sometimes shift their date by one day (in rare cases by two days).