Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

problems with Java daylight savings time

Tags:

java

timezone

dst

I have a Java app that needs to be cognizant of the time zone. When I take a Unix epoch time and try to convert it into a timestamp to use for an Oracle SQL call, it is getting the correct timezone, but the timezone "useDaylightTime" value is not correct, i.e., it is currently returning "true", when we are NOT in DST (I am in Florida in TZ "America/New_York").

This is running on Red Hat Linux Enterprise 6, and as far as I can tell, it is correctly set up for the timezone, e.g. 'date' returns: Wed Nov 28 12:30:12 EST 2012

I can also see, using the 'zdump' utility, that the current value for 'isdst' is 0.

My Java version is 1.6.0_31.

I have Googled this and seen the numerous issues this has caused, but many of them simply say to set the TZ manually, but my issue is not the TZ, but the fact that the default TZ has the "isDaylight" set to 'true'. I believe this is causing my query to return data that is one hour off (I can see that it is).

Here is a simple code piece I have run to try and reproduce this in the simplest way possible:

public class TZdefault {

    public static void main(String[] args) throws IOException {

            long startTime = System.currentTimeMillis()/1000;

            Calendar start = Calendar.getInstance();
            start.setTimeInMillis(startTime);

            start.setTimeZone(TimeZone.getDefault());

            System.out.println("Start UTC: " + start + "ms: " + start.getTimeInMillis());
            System.out.println("use daylight: " + start.getTimeZone().useDaylightTime());

    } // end main


}  // end class

One final thing. If in my code I set the TZ to "EST", it of course does return a TZ with 'isDaylight' set to False. But that is not a good solution.

I wanted to add some more detail that I had been hoping to hide.

I have records in an Oracle 11g database that use TIMESTAMP with TIMEZONE fields. I am simply doing JDBC queries where two of the parameters are using BETWEEN a start timestamp and end timestamp.

When I query this table, I am using a prepared statement that is using a Calendar entry, the sole purpose of which was to try and manipulate the timezone. The bottom line is that I am doing a pstmt.setTimestamp() call using the 'getTimeInMillis' method for the start and end time after the "default" timezone was applied. The log output shows that in fact it is putting in the correct milliseconds, but the returned SQL results are clearly off by one hour exactly!

I am still trying to verify that there is not an issue on the data insertion side as well.

But I have a lot of debug information, and it looks like I am asking for the correct time in my JDBC query.

like image 529
mitchmcc Avatar asked Nov 28 '12 17:11

mitchmcc


2 Answers

the timezone useDaylightTime value is not correct, i.e., it is currently returning "true", when we are NOT in DST

I think you're confusing useDaylightTime with inDaylightTime. The former tells you whether there is a transition between daylight time and standard time in the future, not which side of that transition you're on. For example, it returns false for Chinese time zones because China does not adjust for daylight savings time, but it returns true for most US time zones because most US states (except Arizona) do observe daylight savings time.

inDaylightTime

public abstract boolean inDaylightTime(Date date)

Queries if the given date is in Daylight Saving Time in this time zone.

vs

useDaylightTime

public abstract boolean useDaylightTime()

Queries if this TimeZone uses Daylight Saving Time. If an underlying TimeZone implementation subclass supports historical and future Daylight Saving Time schedule changes, this method refers to the last known Daylight Saving Time rule that can be a future prediction and may not be the same as the current rule. Consider calling observesDaylightTime() if the current rule should also be taken into account.

like image 191
Mike Samuel Avatar answered Oct 01 '22 15:10

Mike Samuel


If you want to disable daylight saving calculation, then you must set your timezone to EST. Else otherwise time will be calculated based on default time zone set for AMERICA/NEW_YORK

       TimeZone zoneEST = TimeZone.getTimeZone("EST"); 
       System.out.println(zoneEST.getDSTSavings());  //0 hour
       System.out.println(zoneEST.getRawOffset());  //5 hour
       TimeZone.setDefault(zoneEST);
       System.out.println("");

       TimeZone zoneNY = TimeZone.getTimeZone("America/New_York");
       System.out.println(zoneNY.getDSTSavings()); // 1 hour
       System.out.println(zoneNY.getRawOffset()); // 5 hour
like image 36
Vishal Avatar answered Oct 01 '22 14:10

Vishal