[JAVA] Be careful of daylight saving time when newly registering / referencing a user's birthday

1. Overview

Convert to milliseconds on the front side When sending time information to the backend API You need to consider daylight savings time.

If you convert it with a Java method, it will handle daylight saving time, This is because javascript does not handle it.

In this article, how Java handles daylight savings time I will tell you the detailed specifications of the conversion.

problem

The birthday of a person born during daylight saving time An event has occurred that is displayed one day off.

Solution

1 hour during registration / reference during daylight saving time You need to add and subtract milliseconds.

2. Details

The period for introducing daylight saving time in Japan is as follows.

Year Start time End time
1948 (Showa 23) May 2(Day)2 am 9月11Day(soil)2 am
1949 (Showa 24) April 3(Day)2 am 9月10Day(soil)2 am
1950 (Showa 25) May 7(Day)2 am 9月9Day(soil)2 am
1951 (Showa 26) May 6(Day)2 am 9月8Day(soil)2 am

Date and time ⇒ milliseconds

Start of summer time

May 2nd (Monday) at 2:00 am to enter daylight saving time The time is advanced by one hour and the millisecond is the same as 3:00 am.

** Verification source **

SummerTime.java


import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class SummerTime {
	public static void main(String[] args) throws ParseException {
		convertToMilliseconds("1948-05-02 02:00:00");
		convertToMilliseconds("1948-05-02 03:00:00");
	}

	private static void convertToMilliseconds(String dateStr) throws ParseException {
		SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		Date date = formatter.parse(dateStr);
		System.out.println(dateStr + " -> " + date.getTime());
	}
}

** Output result **

1948-05-02 02:00:00 -> -683794800000
1948-05-02 03:00:00 -> -683794800000

The conversion at 2:00 am is as follows.

1948-05-02 02:00:00 -> -683794800000
1948-05-02 02:00:01 -> -683794799000
1948-05-02 02:00:02 -> -683794798000
・
・
・
1948-05-02 02:59:58 -> -683791202000
1948-05-02 02:59:59 -> -683791201000
1948-05-02 03:00:00 -> -683794800000

From 2:59:59:999 to 3:00 am I understand the specifications to be corrected. However, there is no 2:00 am during daylight saving time. It is not expected that the millisecond conversion between 2 and 3 o'clock will be used.

End of summer time

To get out of daylight saving time at 1:00 am on Monday, September 11 The time must be restored by one hour.

1948-09-11 00:59:59 -> -672397201000
1948-09-11 01:00:00 -> -672393600000

The difference is 1 second in the date and time notation, In milliseconds, it is corrected to 360 1000 milliseconds.

Milliseconds ⇒ date and time

Start of summer time

Now let's switch back to the date and time notation from milliseconds.

** Verification source **

SummerTime.java


private static void convertToTimeFormat(Long milliSeconds) throws ParseException {
	SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
	String dateStr = formatter.format(milliSeconds);
	System.out.println(milliSeconds + " -> " + dateStr);
}

** Output result **

-683794801000 -> 1948-05-02 01:59:59
-683794800000 -> 1948-05-02 03:00:00
-683794799000 -> 1948-05-02 03:00:01

End of summer time

-672397201000 -> 1948-09-11 00:59:59
-672397200000 -> 1948-09-11 01:00:00
-672397199000 -> 1948-09-11 01:00:01
・
・
・
-672393601000 -> 1948-09-11 01:59:59
-672393600000 -> 1948-09-11 01:00:00
-672393599000 -> 1948-09-11 01:00:01

The specifications are such that the 1 am level comes twice.

3. Remedy

When converting at the front, correct the milliseconds of the corresponding period Fixed to send time information to API.

dateUtil.ts


    /**
     *Get time considering daylight saving time (converted when displaying from API to front)
     */
    export function getSummerTimeDate(birthDate){
        let birth = Number(birthDate)
        if ((birth >= -683794800000 && birth <= -672393600001)
            || (birth >= -654764400000 && birth <= -640944000001)
            || (birth >= -620290800000 && birth <= -609494400001)
            || (birth >= -588841200000 && birth <= -578044800001)) {
            birth += 3600000
        }
        return birth
    }

    /**
     *Substitute time considering daylight saving time (converted when registering from front to API)
     */
    export function setSummerTimeDate(birthDate){
        let birth = Number(birthDate)
        if ((birth >= -683791200000 && birth <= -672390000001)
            || (birth >= -654760800000 && birth <= -640940400001)
            || (birth >= -620287200000 && birth <= -609490800001)
            || (birth >= -588837600000 && birth <= -578041200001)) {
            birth -= 3600000
        }
        return birth
    }

4. Summary

I think it is better to consider whether to handle the time of daylight saving time introduction at the stage of considering the specifications. Also, I think we should consider another way to avoid it, such as using UTC for the time zone.

5. Reference

Japanese Daylight Saving Time and Java About the real summer time

Recommended Posts

Be careful of daylight saving time when newly registering / referencing a user's birthday
Be absolutely careful when putting the result of and / or in a variable!
[Technical memo] Things to be careful of from an engineer's point of view when creating a view
Be careful of initialization timing when using MessageEncryptor with Rails 5.2 / 6.0