I am looking at the SimpleDateFormat in Java.
I want to format a date string and turn it into a Date/Calendar, then format the resulting date/calendar back to the string. This is for a date time over the October clock change where you have two 03:00’s in the day. The times over the October clock change period should be:
** UPDATE I have changed my times from 01:00 to 03:00 where there should be 2 times in the day **
- 2012-10-28 02:00:00 CEST
- 2012-10-28 02:30:00 CEST
- 2012-10-28 02:00:00 CET
- 2012-10-28 02:30:00 CET
- 2012-10-28 03:00:00 CET
Converting 2012-10-28 01:00:00 CET to date/calendar then back to string is causing the issue. The converted string is 2012-10-28 02:00:00 CEST – which does not exist.
The following code will replicate this problem:
public class DatesAndTimesStackOverflow {
final static SimpleDateFormat sdf;
final static TimeZone tz;
static {
tz = TimeZone.getTimeZone( "Europe/Paris" );
sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss zzz");
sdf.setTimeZone(tz);
}
public static void main(String[] args) {
// october clock change should be the following:
outputDateInfo("2012-10-28 02:00:00 CEST");
outputDateInfo("2012-10-28 02:30:00 CEST");
outputDateInfo("2012-10-28 02:00:00 CET");
outputDateInfo("2012-10-28 02:30:00 CET");
outputDateInfo("2012-10-28 03:00:00 CET");
outputDateInfo("2012-10-28 03:30:00 CET");
outputDateInfo("2012-10-28 04:00:00 CET");
}
private static void outputDateInfo(String theDate) {
try {
output("------------------------------------------------------------------------------");
Date d = sdf.parse(theDate);
Calendar c = GregorianCalendar.getInstance(tz);
c.setTimeInMillis(d.getTime());
TimeZone tzCal = c.getTimeZone();
output("String: " + theDate);
output("");
output("Date: " + d); // toString uses current system TimeZone
output("Date Millis: " + d.getTime());
output("Cal Millis: " + c.getTimeInMillis());
output("Cal To Date Millis: " + c.getTime().getTime());
output("Cal TimeZone Name: " + tzCal.getDisplayName());
output("Cal TimeZone ID: " + tzCal.getID());
output("Cal TimeZone DST Name: " + tzCal.getDisplayName(true, TimeZone.SHORT));
output("Cal TimeZone Standard Name: " + tzCal.getDisplayName(false, TimeZone.SHORT));
output("In DayLight: " + tzCal.inDaylightTime(d));
output("");
output("Day Of Month: " + c.get(Calendar.DAY_OF_MONTH));
output("Month Of Year: " + c.get(Calendar.MONTH));
output("Year: " + c.get(Calendar.YEAR));
output("Hour Of Day: " + c.get(Calendar.HOUR_OF_DAY));
output("Minute: " + c.get(Calendar.MINUTE));
output("Second: " + c.get(Calendar.SECOND));
// check to see if this converts back to correct string
String reformat = sdf.format(c.getTime());
if( reformat.equals(theDate) ) {
output("ReConvert: " + reformat + " OK");
} else {
output("ReConvert: " + reformat + " <-------- Error. The converted date is different");
}
} catch (ParseException ex) {
output("Cannot parse this date");
}
}
private static void output(String message) {
System.out.println(message);
}
}
I don’t think it is a problem with my example. Hopefully it is and not a problem in Java. Is there a rational explanation if it is not the way I have coded this?
It is correct. There is such a time as 2:00 (or 3) CEST. Europe/Paris contains two timezones, CET and CEST. They are always an hour apart and are both contiguous (the timezone’s UTC offset never changes, the calendar switches timezones).
Also note, fall backward happens at 3 in the morning, not at 1 in the morning! If you change your times to 3, you should see it flip the other way, where parsing 3:00CET input yields 3:00CET output, but parsing 3:00CEST input, yields 2:00CET output, as expected.
At 3am in Paris, the current time changes from 3:00 CEST to 2:00 CET. When you specify Oct 28, 2012 3:00 CEST as your input, it will end up outputting 2:00am CET, which is the same actual point in time, because that is what clocks on the wall in Paris say!
—
I think there is some confusion about the ‘human’ meaning of CET vs the machine meaning. To a person “CET” for Paris means “A location that is +1 hour UTC in the winter and +2 hours UTC in the summer.” However, when you see output printed by the parser, CET means +1 hours, always. So when you print Paris times that happen before the “first” 3:00 am on 10/28, the parser is going to output it as CEST. When you print Paris times that happen after the “first” 3am on Oct 28, it will say CET.
At the time of the daylight saving switch Parisians will experience both 02:59 CET (machine meaning) and 02:59 CEST, rather than “02:59 CET twice” as might be a more human understanding. They’re both valid times that exist.