Android time zone and DST issue

Randy picture Randy · Mar 16, 2013 · Viewed 8.7k times · Source

I have an application which uses a schedule. The user picks what time the schedule should start/end, and I display that start/end time back to the user. Problem is, the time that is displayed back is off, since the DST change.

I can fix the issue for my time zone (Eastern time) or I can fix the issue for GMT, and if I setup a specific case for GMT, Alaskan time is still wrong. Any suggestions?

here's my code:

the time that is being displayed:

long startTimeMillis = (startHour * 1000 * 60 * 60) + (startMin * 1000 * 60) - getTimeOffset();

getTimeOffset:

TimeZone tz = TimeZone.getDefault();

//deal with GMT weirdness
if (tz.getRawOffset() == 0)
    return tz.getRawOffset() + tz.getDSTSavings();
else
    return tz.getRawOffset();

I would think that I need something like:

else if(tz.inDaylightTime(new Date()))
    return tz.getRawOffset() + tz.getDSTSavings();

But if I do that, then Eastern time shows 1 hour less than it should, and Alaskan time shows 2 hours less. If I do the opposite: (- instead of +)

else if(tz.inDaylightTime(new Date()))
    return tz.getRawOffset() - tz.getDSTSavings();

Then Eastern time is 1 hour more than it should be, but Alaskan time is correct.

ADDENDUM:

I've also tried using tz.getOffset(new Date().getTime()) in each of those situations instead of tz.getRawOffset(). This was actually the first thing that I tried, because according to Google's documentation, this function is supposed to handle DST for you.

END ADDENDUM

I've also tried using Calendars, like this:

Calendar calendar = GregorianCalendar.getInstance();

return calendar.get(Calendar.ZONE_OFFSET);

This gives the correct time for EST time, but 1 hour ahead for GMT and 1 hour behind for Alaska. And I've tried this:

if(tz.inDaylightTime(new Date()))
    return calendar.get(Calendar.ZONE_OFFSET) + calendar.get(Calendar.DST_OFFSET);
else
    return calendar.get(Calendar.ZONE_OFFSET);

But this leaves EDT 1 hour short.

I've also tried this:

return tz.getOffset(calendar.get(Calendar.ERA),
            calendar.get(Calendar.YEAR),
            calendar.get(Calendar.MONTH),
            calendar.get(Calendar.DAY_OF_MONTH),
            calendar.get(Calendar.DAY_OF_WEEK),
            calendar.get(Calendar.MILLISECOND));

which leaves EDT 1 hour short as well.

And I get the same results if I use

GregorianCalendar calendar = new GregorianCalendar(tz);

instead of

Calendar calendar = GregorianCalendar.getInstance();

How do I do this correctly???

Answer

Randy picture Randy · Mar 18, 2013

OK, I finally figured out how to do it properly. This is how I made it work:

long startTimeMillis = (startHour * 1000 * 60 * 60) + (startMinute * 1000 * 60);
startTimeMillis  -= getTimeOffset(startTimeMillis);

getTimeOffset():

public static int getTimeOffset(long time)
{
    TimeZone tz = TimeZone.getDefault();

    return tz.getOffset(time);
}