Question

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???

Was it helpful?

Solution

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);
}

OTHER TIPS

Sounds like you're setting the emulator timezone, which you are retrieving via tz.getDefault(). Calendars will handle daylight savings times internally - IF they are set to a TimeZone that observes daylight savings at all. Some of the TimeZones, such as "America/Phoenix" and "MDT" don't observe savings time, while "America/Denver" does.

The Alaska Time Zone observes standard time by subtracting nine hours from Coordinated Universal Time (UTC−9). During daylight saving time its time offset is eight hours (UTC−8). https://en.wikipedia.org/wiki/Alaska_Time_Zone

You can use TimeZone.getAvailableIDs() to get a list of all the TimeZone names/keys. Check out the differences between America/Anchorage, Etc/GMT+9, America/Alaska.

EDIT: updated code Here's some example code you a couple ways you can play around with dates and DST:

package com.codeshane.examples;

import java.text.DateFormat;
import java.util.Calendar;
import java.util.TimeZone;

public class Times {
public static final String[] yourZoneKeys =
  {"America/Anchorage", "America/Juneau", "America/Nome", "America/Yakutat",
   "Etc/GMT+9", "Pacific/Gambier", "SystemV/YST9", "SystemV/YST9YDT","US/Alaska"};

public static void main(String[] args){
    for (String timezoneKey: yourZoneKeys){
        TimeZone tz = getSelectedTimezone(timezoneKey);
        displayTimezoneInfo(tz);
        showTimeInNewCalendar(tz);
    }       
}

static void displayTimezoneInfo(TimeZone tz){
    System.out.println(
      "\n> TZ ID:" + tz.getID() +
      "  Display:" + tz.getDisplayName() +
      "  savings:" + tz.getDSTSavings() +
      "   offset:" + tz.getRawOffset() +
      ""
    );
}

static void showTimeInNewCalendar(TimeZone tz) {
    DateFormat df = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL);

    /***** DST US 2013 = Mar 10 - Nov 3
     * Daylight Saving Time (United States) 2013
     * began at 2:00 AM on Sunday, March 10
     *  ends at 2:00 AM on Sunday, November 3
     **/

    //The Calendar method output the same results, but since both
    //methods went through the DateFormat, I went ahead and just
    //used the DateFormat's internal date via getCalendar().set(..)
    //but left the Calendar code (commented out) for you to compare.

    //Calendar gc = Calendar.getInstance();
    //gc.setTimeZone(tz);
    //gc.set(2013, 2, 10, 1, 30, 0);

    // Setting the Calendar's date and time
    df.getCalendar().set(2013, 2, 10, 1, 30, 0);

    // Display some times at 30 minute intervals
    for (int i =0;i<3;i++){

        df.setTimeZone(tz);
        System.out.println(
          "\n " + tz.getID() +
          " " + df.format(df.getCalendar().getTime()) +// sdf. .format(myDateFormat, gc) +
          //" gc date:" + df.format(gc.getTime()) +
          "  " + tz.inDaylightTime(df.getCalendar().getTime()) +
          ""
        );
        df.getCalendar().add(Calendar.MINUTE, 30);
        //gc.add(Calendar.MINUTE, 30);
    }
}

private static TimeZone getSelectedTimezone(String timezoneKey){
    if (null==timezoneKey) return TimeZone.getDefault(); // system/network-provided
    return TimeZone.getTimeZone(timezoneKey); // Gets specified tz, or "GMT" if tzKey is invalid
}

}

EDIT: added output You'll notice some of the timezones spring forward when 30 minutes is added at the "Spring forward" time we just observed on 3/10/2013, while others don't. If you select these timezones that observe DST, you'll get the change; whereas the others won't.

TZ ID:America/Anchorage Display:Alaska Standard Time savings:3600000 offset:-32400000

America/Anchorage Sunday, March 10, 2013 1:30:00 AM AKST false

America/Anchorage Sunday, March 10, 2013 3:00:00 AM AKDT true

America/Anchorage Sunday, March 10, 2013 3:30:00 AM AKDT true

TZ ID:America/Juneau Display:Alaska Standard Time savings:3600000 offset:-32400000

America/Juneau Sunday, March 10, 2013 1:30:00 AM AKST false

America/Juneau Sunday, March 10, 2013 3:00:00 AM AKDT true

America/Juneau Sunday, March 10, 2013 3:30:00 AM AKDT true

TZ ID:America/Nome Display:Alaska Standard Time savings:3600000 offset:-32400000

America/Nome Sunday, March 10, 2013 1:30:00 AM AKST false

America/Nome Sunday, March 10, 2013 3:00:00 AM AKDT true

America/Nome Sunday, March 10, 2013 3:30:00 AM AKDT true

TZ ID:America/Yakutat Display:Alaska Standard Time savings:3600000 offset:-32400000

America/Yakutat Sunday, March 10, 2013 1:30:00 AM AKST false

America/Yakutat Sunday, March 10, 2013 3:00:00 AM AKDT true

America/Yakutat Sunday, March 10, 2013 3:30:00 AM AKDT true

TZ ID:Etc/GMT+9 Display:GMT-09:00 savings:0 offset:-32400000

Etc/GMT+9 Sunday, March 10, 2013 1:30:00 AM GMT-09:00 false

Etc/GMT+9 Sunday, March 10, 2013 2:00:00 AM GMT-09:00 false

Etc/GMT+9 Sunday, March 10, 2013 2:30:00 AM GMT-09:00 false

TZ ID:Pacific/Gambier Display:Gambier Time savings:0 offset:-32400000

Pacific/Gambier Sunday, March 10, 2013 1:30:00 AM GAMT false

Pacific/Gambier Sunday, March 10, 2013 2:00:00 AM GAMT false

Pacific/Gambier Sunday, March 10, 2013 2:30:00 AM GAMT false

TZ ID:SystemV/YST9 Display:Alaska Standard Time savings:0 offset:-32400000

SystemV/YST9 Sunday, March 10, 2013 1:30:00 AM AKST false

SystemV/YST9 Sunday, March 10, 2013 2:00:00 AM AKST false

SystemV/YST9 Sunday, March 10, 2013 2:30:00 AM AKST false

TZ ID:SystemV/YST9YDT Display:Alaska Standard Time savings:3600000 offset:-32400000

SystemV/YST9YDT Sunday, March 10, 2013 1:30:00 AM AKST false

SystemV/YST9YDT Sunday, March 10, 2013 2:00:00 AM AKST false

SystemV/YST9YDT Sunday, March 10, 2013 2:30:00 AM AKST false

TZ ID:US/Alaska Display:Alaska Standard Time savings:3600000 offset:-32400000

US/Alaska Sunday, March 10, 2013 1:30:00 AM AKST false

US/Alaska Sunday, March 10, 2013 3:00:00 AM AKDT true

US/Alaska Sunday, March 10, 2013 3:30:00 AM AKDT true

I also recommend http://www.worldtimeserver.com as it will let you compare your results with what they should be.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top