[이 글의 목적]
서머타임을 이해하고 서머타임으로 인해 발생할 수 있는 이슈를 공유
[서머타임(daylight saving time) 이란?]
서머타임은 특히 하절기에 국가의 표준시를 원래 시간보다 (일반적으로) 한 시간 앞당겨 사용하는 것을 말합니다.
https://www.worlddata.info/timezones/daylightsavingtimes.php
미국 주식을 해보신 분들이라면 아마 "아~ 그거" 라고 하시면서 바로 아실 겁니다.
미국 주식 시장 시작 시각이 서머타임에 영향을 받는 대표적인 예 입니다.
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시간을 앞으로 당겼기 때문입니다.
[마무리]
서머타임으로 인해 구현방식에 따라서 버그가 발생할 수 있습니다.
글로벌 서비스를 개발하시거나 운영하신다면 도움이 될 수 있는 서머타임에 관하여 정리해보았습니다.
'개발' 카테고리의 다른 글
자바 ArrayList 의 default size 는 10 맞을까? (0) | 2023.02.19 |
---|---|
알면 유용한 Java 8, 9 에서 추가, 변경된 Collection 관련 내용 (0) | 2023.02.11 |
자바 8 stream 의 lazy (0) | 2023.02.05 |
자바 8 람다는 익명 클래스와 같을까? (0) | 2023.01.30 |
AWS S3 + CloudFront + 커스텀 도메인(HTTPS) 웹사이트 배포하기 (0) | 2022.12.25 |