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???
Google Calendar uses Coordinated Universal Time (UTC) to help avoid issues with daylight saving time. When events are created, they're converted into UTC, but you'll always see them in your local time. If an area switches their time zone, events created before we knew about the change might be in the wrong time zone.
The simplest way to remember "time zone math" for the states that recognize Daylight saving time is three-two-one: three hours difference from Eastern to Pacific, two hours difference from Eastern to Mountain, and one hour difference from Eastern to Central.
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);
}
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.
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