[JAVA] Daylight saving time problem also in Japan

When it comes to daylight saving time, there have been talks about introducing daylight saving time as a measure against the heat of the Olympic Games. It was impossible, and this story flowed as it was. As long as I was in Japan, I thought that daylight saving time had nothing to do with it, but I stepped on a bug caused by daylight saving time in Japan. This article is the end of it.

One day less for some reason

I was running a loop like this to create data about dates:

Calendar cal = new GregorianCalendar(1900,  1 - 1,  1, 0, 0, 0);
Calendar end = new GregorianCalendar(2020, 12 - 1, 31, 0, 0, 0);
long endTime = end.getTimeInMillis();

while (cal.getTimeInMills() <= endtime) {
     // (Date data creation)
     cal.add(Calendar.DATE, 1);
}

I am trying to create data from 1900/01/01 to 2020/12/31. However, the date data created is one day less. Data should be created until 12/31/2020, but only until 12/30/2020. So when I look at the contents of the date,

1900/01/01 00:00:00.000
1900/01/02 00:00:00.000
1900/01/03 00:00:00.000

(Omission)

2020/12/28 01:00:00.000
2020/12/29 01:00:00.000
2020/12/30 01:00:00.000

Somewhere off by an hour. ʻEnd time` pointed to 2020/12/31 00: 00: 00.000, so it seems that the result is one day less.

Does not occur with older JDKs

This happened on the jdk-8u191, but it didn't happen on older JDKs.

1900/01/01 00:00:00.000
1900/01/02 00:00:00.000
1900/01/03 00:00:00.000

(Omission)

2020/12/28 00:00:00.000
2020/12/29 00:00:00.000
2020/12/30 00:00:00.000
2020/12/31 00:00:00.000

And it works as expected. If you look in more detail,

I found out. Did Degres get mixed in with the JDK during this time? I went through various things, but I couldn't find any pages like this. Then, when I looked up where it was off,

1948/04/29 00:00:00.000
1948/04/30 00:00:00.000
1948/05/01 00:00:00.000
1948/05/02 01:00:00.000
1948/05/03 01:00:00.000
1948/05/04 01:00:00.000

It is off at 1948/05/02. I thought, and when I went around in Japan's daylight saving time

[Daylight Saving Time Application Period](https://ja.wikipedia.org/wiki/%E5%A4%8F%E6%99%82%E5%88%BB%E6%B3%95#%E5%A4%8F% E6% 99% 82% E9% 96% 93% E9% 81% A9% E7% 94% A8% E6% 9C% 9F% E9% 96% 93)

It coincides with the first day of daylight saving time in Japan, May 2, 1948. Did this happen because the Japanese summertime was implemented in the jdk-8u171? ?? ??

JDK Changelog

I can't find any description about daylight saving time in Japan by looking at Changelog of jdk-8u171.

Looking at Timezone Data Versions in the JRE Software, there were changes related to Japan around 2014. Can be read, but there is no such thing in jdk-8u171.

If you take a closer look at the Changelog of jdk-8u171 above, you will find the following description.

IANA Data 2018c JDK 8u171 contains IANA time zone data version 2018c. For more information, refer to Timezone Data Versions in the JRE Software.

Timezone data has been updated. So, I will try to hit this.

Daylight saving time data (Timezone data)

https://www.iana.org/time-zones

Seems to be the source of Timezone data. Looking at the difference between tzdb-2018c and the previous tzdb-2018b,

tzdb-2018b 2018-01-18 08:50 asia:

# Rule	NAME	FROM	TO	TYPE	IN	ON		AT	    SAVE	LETTER/S
Rule	Japan	1948	only	-	May	Sun>=1	2:00	1:00	D
Rule	Japan	1948	1951	-	Sep	Sat>=8	2:00	0		S
Rule	Japan	1949	only	-	Apr	Sun>=1	2:00	1:00	D
Rule	Japan	1950	1951	-	May	Sun>=1	2:00	1:00	D

tzdb-2018c 2018-01-23 10:30 asia:

# Rule	NAME	FROM	TO	TYPE	IN	ON		AT		SAVE	LETTER/S
Rule	Japan	1948	only	-	May	Sat>=1	24:00	1:00	D
Rule	Japan	1948	1951	-	Sep	Sat>=8	25:00	0		S
Rule	Japan	1949	only	-	Apr	Sat>=1	24:00	1:00	D
Rule	Japan	1950	1951	-	May	Sat>=1	24:00	1:00	D

And certainly there are changes. How to read this

# Rule	NAME	FROM	TO	TYPE	IN	ON		AT	    SAVE	LETTER/S
Rule	Japan	1948	only	-	May	Sun>=1	2:00	1:00	D
(First Saturday of May 1948(First Saturday after 1st)of 2:Advance to 00 for 1 hour)

It seems that. The new one is

# Rule	NAME	FROM	TO	TYPE	IN	ON		AT	    SAVE	LETTER/S
Rule	Japan	1948	only	-	May	Sun>=1	24:00	1:00	D
(First Saturday of May 1948(First Saturday after 1st)24:Advance to 00 for 1 hour)

And the start time of summer time has been changed. In other words, if you change 0 o'clock to 1 o'clock. Ah!

What was happening

The jdk-8u171 has an update for daylight saving time in Japan. This changes the start time of daylight saving time from 2 o'clock to 0 o'clock. Since the original program was running at 00:00:00

Was off by one hour. Until then, the start time was 2:00 am, so

As a result, I was able to calculate the date without losing it.

Countermeasures

Since the cause has been clarified, it is a countermeasure. How to overcome this problem.

Set the end time to +1 day-1 millisecond

Since the end time was 2018/12/31 00:00:00, it was one day less. Isn't there any problem if this is set to 2018/12/31 23:59:59?

Calendar end = new GregorianCalendar(2020, 12 - 1, 31, 0, 0, 0);
end.add(Calendar.DATE, 1)
end.add(Calendar.MILLISECOND, -1)
long endTime = end.getTimeInMillis(); // 2018/12/31 23:59:59.999

Certainly this fix worked as intended. However, it's really unpleasant that the date on the way points to 01:00:00. Even if it works here, it can cause problems elsewhere.

+24 hours

Since it is cal.add (Calender.DATE, 1), it will be shifted, and if it is cal.add (Calender.HOUR, 24), it will not be shifted. Sure, the program still worked as intended. However, if you look at the time

1948/04/29 00:00:00.000
1948/04/30 00:00:00.000
1948/05/01 00:00:00.000
1948/05/02 01:00:00.000
1948/05/03 01:00:00.000
1948/05/04 01:00:00.000
...
1948/09/09 01:00:00.000
1948/09/10 01:00:00.000
1948/09/11 01:00:00.000
1948/09/12 00:00:00.000
1948/09/13 00:00:00.000
1948/09/14 00:00:00.000

After all it is off on the way. So the same problem occurs if the end date is 09/09/1948. It's unlikely to happen in practice, but it's a potential bug and I'd like to avoid it if possible.

+1 day .set (00:00:00)

How about always setting the time to 00: 00: 00.000 after +1 day?

cal.add(Calendar.DATE, 1);
cal.set(Calendar.HOUR, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);

Then

1948/04/29 00:00:00.000
1948/04/30 00:00:00.000
1948/05/01 00:00:00.000
1948/05/02 01:00:00.000 //There is no help for it here
1948/05/03 00:00:00.000
1948/05/04 00:00:00.000
...
1948/09/09 00:00:00.000
1948/09/10 00:00:00.000
1948/09/11 00:00:00.000
1948/09/12 00:00:00.000
1948/09/13 00:00:00.000
1948/09/14 00:00:00.000

It is the intended operation. However, it feels redundant to set 00: 00: 00.00 every time. I rarely work with 1948 data, so I don't want to be able to clear the time every time.

Use LocalDate

Then I arrived at using LocalDate. This is one of the Date and Time API introduced from Java8. LocalDate is a date-only class that has no time information, so it is not affected by daylight saving time. The previous code is

LocalDate cal = LocalDate.of(1900,  1,  1);
LocalDate end = LocalDate.of(2018, 12, 31);
long endDay = end.toEpochDay();
			
while (cal.toEpochDay() <= endDay) {
     // (Date data creation)
    cal = cal.plusDays(1); //LocalDate is Immutable
}

You can simply put it in the code as it is without taking any workaround.

What was the problem after all?

It seems that the problem is that common sense does not apply when there is daylight saving time as follows.

I thought it was common sense. Until you step on this bug. .. ..

Finally

I hope that summer time will not be introduced in Japan in the future.

Recommended Posts

Daylight saving time problem also in Japan
About the daylight saving time that really happened
How to set the display time to Japan time in Rails
Various pensions in Japan