Reputation: 1146
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???
Upvotes: 6
Views: 10620
Reputation: 1146
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);
}
Upvotes: 5
Reputation: 6510
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.
Upvotes: 1