HOUR_OF_DAY sets the same hour for value 0 and 1

I have a tricky (at least for me) question with java time zones. I will start with an example that works as expected:

TimeZone tz = TimeZone.getDefault();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat();
simpleDateFormat.setTimeZone(tz);
Calendar calendar = Calendar.getInstance();
calendar.setTimeZone(tz);

calendar.set(Calendar.HOUR_OF_DAY, 0);
System.out.println("0: " + simpleDateFormat.format(calendar.getTime()));

calendar.set(Calendar.HOUR_OF_DAY, 1);
System.out.println("1: " + simpleDateFormat.format(calendar.getTime()));

calendar.set(Calendar.HOUR_OF_DAY, 2);
System.out.println("2: " + simpleDateFormat.format(calendar.getTime()));

output:

0 4/28/17 12:27 AM
1: 4/28/17 1:27 AM
2: 4/28/17 2:27 AM

And now a little of magic:

TimeZone tz = TimeZone.getTimeZone("Africa/Cairo");
SimpleDateFormat simpleDateFormat = new SimpleDateFormat();
simpleDateFormat.setTimeZone(tz);
Calendar calendar = Calendar.getInstance();
calendar.setTimeZone(tz);

calendar.set(Calendar.HOUR_OF_DAY, 0);
System.out.println("0: " + simpleDateFormat.format(calendar.getTime()));

calendar.set(Calendar.HOUR_OF_DAY, 1);
System.out.println("1: " + simpleDateFormat.format(calendar.getTime()));

calendar.set(Calendar.HOUR_OF_DAY, 2);
System.out.println("2: " + simpleDateFormat.format(calendar.getTime()));

output:

0: 4/28/17 1:31 AM
1: 4/28/17 1:31 AM
2: 4/28/17 2:31 AM

Could someone explain me why HOUR_OF_DAY for values 0 and 1 set hour on the same value for specific TimeZone's?

Jon Skeet
people
quotationmark

Your machine has an old version of time zone data, in which Egypt would have put the clocks forward at midnight local time at the start of April 28th 2017. Therefore 12:31am wouldn't have existed, and Java is skipping forward by an hour instead1.

On July 5th 2016, IANA time zone data 2016f was released with the change to the Africa/Cairo time zone to not observe DST from that point onwards. (This was a very late announcement, as the next change would have been July 8th 2016.)

You can see all the transitions for every IANA time zone, across different versions of the IANA data, at http://nodatime.github.io/tzvalidate/. (Disclaimer: I build that page. I started the tzvalidate project to validate that different date/time libraries understand the time zone data in the same way.)


1 I would argue that the API should force you to state what you want to happen in that case, but I won't go into everything that's wrong with java.util.Calendar here...

people

See more on this question at Stackoverflow