본문 바로가기

개발

서머타임(daylight saving time)에 대해 코드와 함께 알아보자

[이 글의 목적]

서머타임을 이해하고 서머타임으로 인해 발생할 수 있는 이슈를 공유

 

[서머타임(daylight saving time) 이란?]

서머타임은 특히 하절기에 국가의 표준시를 원래 시간보다 (일반적으로) 한 시간 앞당겨 사용하는 것을 말합니다.

https://www.worlddata.info/timezones/daylightsavingtimes.php

 

미국 주식을 해보신 분들이라면 아마 "아~ 그거" 라고 하시면서 바로 아실 겁니다.

미국 주식 시장 시작 시각이 서머타임에 영향을 받는 대표적인 예 입니다.

2022 미국 서머타임

2022년 미국 동부에서 서머타임으로 인해 시간 변경은 아래와 같습니다.

(서머타임 시작) 03월 13일  02:00 -> 03월 13일  03:00

(서머타임 종료) 11월 16일 02:00 -> 11월 16일 01:00

 

서머타임이 시작하면 3월13일 02:00 가 되는 순간 저 지역의 사람들은 집에 있는 시계를 3월13일 03시로 고쳐서 사용합니다.

서머타임이 종료하면 11월 16일 02:00 가 되는 순간 11월16일 01시로 고쳐서 사용합니다.

 

이 서머타임의 시작, 종료 시각은 TimeZone에 따라 달라집니다.

보통은 서머타임이 시작되면 시간을 뒤로 미루지만,

예외적으로 시간을 당기는 나라도 있으니 확인을 잘 해야 합니다.

 

코드를 실행하면 어떤 결과가 나오는지 확인해보겠습니다. 

예시는 TimeZone 을 America/New_York 을 사용하였습니다.

 

[서머타임 시작]

 

America/New_York TimeZone에서 2022년 03월 13일 02:00:00 이 서머타임 시작 시각이니까

그 전후를 출력하여 시간이 어떻게 변해가는지 확인해보겠습니다.

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime eventStartDateTime = LocalDateTime.parse("2022-03-13 01:50:00", formatter);

ZonedDateTime eventStartZonedDateTime = ZonedDateTime.of(eventStartDateTime, ZoneId.of("America/New_York"));
for (int i=0; i<80; i++) {
    eventStartZonedDateTime = eventStartZonedDateTime.plusMinutes(1);
    System.out.println(eventStartZonedDateTime);
}

 

시간의 변화는 다음과 같습니다.

01:59 -> 03:00

그러면서 시간의 Offset 또한 -05:00 -> -04:00 로 변경되었습니다.

이 offset 은 UTC 로부터 얼마만큼 시간이 떨어져 있는지에 대한 값인데, 원래 UTC 보다 5시간 빠른 시간이 미국시간이었는데,

서머타임으로 1시간이 미뤄져서 4시간이 빠른 시간으로 바뀌었습니다.

 

그럼 사라져버린 2022-03-13 02:00:00 문자열을 파싱하면 어떤 시간이 나올까요?

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime eventStartDateTime = LocalDateTime.parse("2022-03-13 02:00:00", formatter);

ZonedDateTime eventStartZonedDateTime = ZonedDateTime.of(eventStartDateTime, ZoneId.of("America/New_York"));
System.out.println(eventStartZonedDateTime);
2022-03-13T03:00-04:00[America/New_York]

02:00 를 파싱하면 03시로 파싱이 되는 것을 볼 수 있습니다.

 

[서머타임 종료]

 

America/New_York TimeZone에서 2022년 11월 06일 02:00:00 이 서머타임 종료시각이니까

그 전후를 출력하여 시간이 어떻게 변해가는지 확인해보겠습니다.

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime eventStartDateTime = LocalDateTime.parse("2022-11-06 01:00:00", formatter);

ZonedDateTime eventStartZonedDateTime = ZonedDateTime.of(eventStartDateTime, ZoneId.of("America/New_York"));
for (int i=0; i<130; i++) {
    eventStartZonedDateTime = eventStartZonedDateTime.plusMinutes(1);
    System.out.println(eventStartZonedDateTime);
}

 

시간의 변화는 다음과 같습니다.

01:59 -> 01:00 -> 02:00

01:59 -> 01:00 로 다시 돌아갈 때, offset이 변경되는 것을 볼 수 있습니다.

 

2022-11-06 의 01:00:00 ~ 01:59:59 는 offset 이 -04:00 일 때와 -05:00 일 때 2종류가 됩니다.

 

만약 2022-11-06 01:59:00 문자열을 파싱하면 어떤 결과가 나올까요?

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime eventStartDateTime = LocalDateTime.parse("2022-11-06 01:59:00", formatter);

ZonedDateTime eventStartZonedDateTime = ZonedDateTime.of(eventStartDateTime, ZoneId.of("America/New_York"));
System.out.println(eventStartZonedDateTime);
2022-11-06T01:59-04:00[America/New_York]

결과는 서머타임이 해제되기 전 offset 인 -04:00으로 되었고 시간은 01:59:00 그대로 나왔습니다. 

 

그래서 서머타임이 해제된 시간을 얻고 싶다면 offset과 같이 명시해야 합니다.

ZonedDateTime zdt1 = ZonedDateTime.parse("2022-11-06T01:59:00-05:00[America/New_York]");
System.out.println(zdt1);
2022-11-06T01:59-05:00[America/New_York]

 

 

[주의사항]

 

서머타임으로 인해서 시스템은 의도치 않은 동작을 할 수 있습니다. 

 

미국시간(타임존: America/New_York) 2022-10-24(월요일) 00:00:00 을 기준으로

806400(7일을 초로 환산) 초를 더하면 2022-10-31(월요일) 00:00:00 이 됩니다.

한번 더 806400 초를 더하면 2022-11-07 (월요일) 00:00:00 이 되는게 아니라,

2022-11-06(일요일) 23:00:00 이 됩니다!

서머타임으로 인해 1시간을 앞으로 당겼기 때문입니다.

 

 

[마무리]

서머타임으로 인해 구현방식에 따라서 버그가 발생할 수 있습니다.

글로벌 서비스를 개발하시거나 운영하신다면 도움이 될 수 있는 서머타임에 관하여 정리해보았습니다.