I have timezone related problem.
I have a program in JAVA and MySql database. I do not use any ORM, but I have custom jdbc library which uses mysql connector java v 6.0.4
I send settings as part of the connection string as:
serverTimezone - America/Chicago
useTimezone - true
useJDBCCompliantTimezoneShift - false
useLegacyDatetimeCode - false
I try to select a date from db e.g 2019-02-13
.
Database is located at time zone US/Eastern and server running java program is located at time zone America/Chicago.
There is no way to change the location / time zone of any of the servers.
In Java, I get a date one day backwards (2019-02-12
).
Problem is caused because of timestamp -
1550034000
is 2019-02-13 00:00:00
in US/Eastern
but
1550034000
is 2019-02-12 23:00:00
in America/Chicago
So as the result I have java.sql.Date
object with date 2019-02-12
.
There is no help to add timezone offset because time information is cut off from date.
Can you propose some solution on how to get a proper date without timezone shift?
Edit: I am using serverTimezone
setting but I am not sure if value should be timezone that database is using or it is just overriding timezone of JVM / server running the application.
First, I have read that you can’t in your case, but for other readers I would like to state that the general recommendation is to run everything in UTC, at least when you span more than one time zone. So this would have been the best solution to your issue.
Second, as both I and Gord Thompson have mentioned in comments, the second best solution is to handle dates as LocalDate
, not java.sql.Date
. While the latter only pretends not to have time of day, it really has design problems that make it hard to solve your issue. A LocalDate
really is a date without time of day and without time zone, so should be a bet that is a lot safer (except that database drivers that convert incorrectly to and from LocalDate
have been heard of; I keep my fingers crossed; again running everything in UTC would eliminate those bugs too). Edit: Assuming you can modify your custom JDBC library, here’s how to get a LocalDate
from a ResultSet
:
LocalDate correctDateDirectlyFromDatabase
= yourResultSet.getObject("yourDateColumn", LocalDate.class);
It requires at least JDBC 4.2, you probably have that.
If none of the above is available to you, here comes the way to mend the incorrect Date
you got from the database. It’s a bit of a hack, but will work.
import java.sql.Date;
// …
// Modern ID of the time zone previously known as US/Eastern
ZoneId datebaseTimeZone = ZoneId.of("America/New_York");
Date dateFromDatabase = new Date(TimeUnit.SECONDS.toMillis(1_550_034_000));
System.out.println("Date as retrieved from database (or pretending): " + dateFromDatabase);
long epochMillis = dateFromDatabase.getTime();
ZonedDateTime dateTime = Instant.ofEpochMilli(epochMillis)
.atZone(datebaseTimeZone);
LocalDate realDate = dateTime.toLocalDate();
// Sanity check
if (! realDate.atStartOfDay(datebaseTimeZone).equals(dateTime)) {
throw new IllegalStateException("Failed to convert date correctly from " + datebaseTimeZone + " time zone");
}
System.out.println("Date is " + realDate);
When I ran this in America/Chicago time zone, it printed:
Date as retrieved from database (or pretending): 2019-02-12 Date is 2019-02-13
I have tried running it in other time zones. In some time zones the first line prints 2019-02-12
, in others 2019-02-13
. The last line prints 2019-02-13
in all time zones I have tried.
Now I have given you a LocalDate
. That’s good, this is what you should want to use in your further processing. In case you need a java.sql.Date
for another legacy API that you don’t want to change just yet, convert back to a correct java.sql.Date
this way:
Date oldfashionedJavaSqlDate = Date.valueOf(realDate);
System.out.println("Date converted back to " + oldfashionedJavaSqlDate);
Date converted back to 2019-02-13
And when I say correct, it requires that no one is tampering with the default time zone of your JVM, which is easy for any program running in the JVM to do.
Link: Oracle tutorial: Date Time explaining how to use java.time.
I am using
serverTimezone
setting but I am not sure if value should be timezone that database is using or it is just overriding timezone of JVM / server running the application.
serverTimezone=America/Chicago
means "interpret the results from the server as if the server was using the America/Chicago
time zone regardless of the default time zone that the server is configured to use". So if you used that setting in your connection string you would get Timestamp
values converted to America/Chicago
even though the default time zone for the server is apparently America/New_York
.
However, before committing to that approach you'd want to confirm that the server really is using America/New_York
(which would presumably switch back and forth between Eastern Standard Time and Eastern Daylight Time) and not a fixed offset like UTC-5 (which would always stay on "Eastern Standard Time").
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With