Date one day backwards after select from MySQL DB

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").