JavaScript `Date` 객체는 왜 항상 당신에게 거짓말을 할까?

JavaScript의 `Date` 객체가 개발자들을 속이는 흔한 함정들을 파헤친다. 시간대, 파싱 방식, 일광 절약 시간 등 `Date`를 다룰 때 주의해야 할 문제점들을 실제 사례와 함께 설명한다.

diff --summary

  • JavaScript `Date` 객체는 시간대, 파싱 방식, 일광 절약 시간 등으로 인해 개발자에게 혼란을 준다.
  • `new Date('YYYY-MM-DD')`와 같은 문자열 파싱은 브라우저마다 다른 시간대 기준으로 해석될 수 있다.
  • `Date` 객체는 UTC와 로컬 시간대를 오가며 의도치 않은 날짜 오류를 발생시킨다.
  • 프로덕션에서 날짜 관련 버그는 보고서, 인보이스 등 중요한 비즈니스 로직에 치명적인 영향을 미친다.
  • 날짜와 시간 처리는 `Date` 객체 대신 `Temporal API`나 외부 라이브러리를 사용하는 것이 안전하다.

JavaScript 개발자라면 누구나 한 번쯤 Date 객체 때문에 밤잠을 설치거나 머리를 쥐어뜯어본 경험이 있을 것이다. 보고서 날짜가 하루씩 밀리거나, 인보이스가 엉뚱한 달에 찍히는 등 Date는 언제나 예상치 못한 방식으로 우리를 배신한다. Reddit의 한 글Date 객체가 개발자들에게 거짓말을 하는 주요 함정들을 파헤친다. 결국 Date는 우리에게 가장 많은 버그를 선사하는 고약한 친구인 셈이다.

Date의 흔한 배신 유형들

Date가 거짓말을 하는 가장 흔한 방식은 바로 ‘시간대(timezone)‘다. new Date('2026-07-21')처럼 날짜 문자열만 넘겨주면, 브라우저나 Node.js 환경에 따라 UTC로 해석되거나 로컬 시간대로 해석될 수 있다. 이는 개발자가 의도한 시간과 다른 결과를 초래하며, 특히 전 세계 사용자를 대상으로 하는 서비스에서는 치명적인 버그로 이어진다. 한국에서 잘 작동하던 기능이 뉴욕에서는 하루 전날로 표시되는 식이다.

일광 절약 시간(Daylight Saving Time, DST)도 빼놓을 수 없는 Date의 함정이다. DST가 시작되거나 끝날 때, 시간이 한 시간 앞당겨지거나 뒤로 밀리면서 Date 객체가 엉뚱한 값을 반환할 수 있다. 예를 들어, 특정 날짜의 자정 시간을 계산했는데, DST 때문에 존재하지 않는 시간이 되거나 중복된 시간이 되어버리는 경우가 발생한다. 이런 버그는 1년에 두 번만 나타나기 때문에 발견하기도 어렵고, 디버깅은 더 고통스럽다.

Date는 이렇게까지 우리를 힘들게 하는가?

문제의 핵심은 Date 객체가 UTC와 로컬 시간대 사이를 오가며 혼란을 야기한다는 점이다. Date 객체는 내부적으로 UTC 시간을 기준으로 하지만, getMonth(), getDate() 같은 메서드는 로컬 시간대 기준으로 값을 반환한다. 게다가 Date.parse()new Date(string)처럼 문자열을 파싱할 때는 구현체마다 동작 방식이 다를 수 있어 예측 불가능성이 커진다.

이런 문제들은 결국 프로덕션 환경에서 실제 비즈니스 로직에 심각한 영향을 미친다. 은행 거래 내역, 결제 시간, 사용자 활동 로그 등이 잘못 기록되면 신뢰도 하락은 물론, 법적 문제까지 발생할 수 있다. 결국 Date 객체를 직접 다루는 것은 지뢰밭을 걷는 것과 같다. Date를 다룰 때는 항상 UTC를 기본으로 하고, 사용자에게 보여줄 때만 로컬 시간대로 변환하는 것이 좋다. 아니면 Temporal API처럼 더 견고한 대안이나 date-fns, Luxon 같은 외부 라이브러리를 쓰는 것이 정신 건강에 이롭다. Date 객체가 당신에게 거짓말을 하는 것이 아니라, 당신이 Date의 거짓말에 속아 넘어가는 것일지도 모른다.

$ sources

  1. [1] Your JS Date Is Lying to You - the traps that keep shipping to production