"0"의 역설: 망가진 첫인상
JavaScript의 Date 클래스는 근본적으로 결함이 있으며, 유용함보다 좌절감을 더 많이 유발하는 유물입니다. Better Stack의 영상 "JavaScript의 Date 클래스를 얼마나 잘 알고 계신가요?"에서 나오는 간단한 퀴즈는 이러한 시스템적 결함을 즉시 드러냅니다. new Date('0')을 입력하면 2000년이 반환됩니다. 하지만 new Date(0)은 정확히 Unix epoch인 1970년 1월 1일 00:00:00 UTC를 반환합니다. 여기서 문자열과 숫자의 구분은 30년이라는 차이를 만들어내며, 이는 매우 당혹스러운 첫인상을 남깁니다.
이러한 혼란은 Date.parse()에서 더욱 깊어집니다. 이 메서드는 문자열만 처리하므로 Date.parse(0)은 먼저 숫자 0을 문자열 '0'으로 강제 변환합니다. 결과적으로 Date.parse('0')과 Date.parse(0) 모두 2000년을 반환합니다. 그 기저에 깔린 논리는 알 수 없으며, 개발자들은 예상치 못한 강제 변환에 끊임없이 주의를 기울여야 합니다.
부조리는 0을 넘어섭니다. new Date('2')를 생각해 보세요. 누군가는 오류가 발생하거나 epoch가 반환될 것이라 예상하겠지만, JavaScript는 이를 2001년 2월로 해석합니다. 이러한 임의적인 파싱은 구현체별 휴리스틱(implementation-specific heuristics)이라고밖에 설명할 수 없는 방식에서 비롯되며, 한 자리 숫자 문자열이 모호하게 연도나 월로 변환됩니다. 이러한 예측 불가능성 때문에 Date 객체는 도구가 아닌 지뢰밭이 됩니다.
가변성과 시간대의 지뢰밭
파싱의 기이함을 넘어, JavaScript의 Date 객체는 끊임없는 좌절의 원인이 되는 근본적인 설계 결함을 가지고 있습니다. 가변성(mutability)은 가장 큰 문제입니다. setDate()나 setMonth()와 같은 메서드는 Date 인스턴스를 직접 변경하여 애플리케이션 전반에 걸쳐 교묘한 부작용을 일으킵니다. Date 객체를 함수에 전달하고 수정하면, 명시적인 경고 없이 원래 참조값이 변경되어 디버깅의 악몽을 초래합니다.
또한 악명 높은 시간대 문제가 있습니다. Date 객체는 사용자의 현지 시간대로 강제로 변환하기 때문에 만연한 하루 차이(off-by-one-day) 오류를 발생시킵니다. UTC 문자열로 생성된 날짜는 올바르게 보일 수 있지만, 이후 getDate()나 getMonth()를 호출하면 현지 오프셋이 자정을 넘기면서 완전히 다른 날짜나 월을 반환할 수 있습니다. 현지 시간과 UTC 시간 사이의 이러한 모호함은 끊임없는 함정입니다.
마지막으로 API 자체는 잘못된 설계의 전형입니다. 월은 0부터 시작하는 인덱스(zero-indexed)를 사용하므로 1월은 0, 12월은 11입니다. 이는 끊임없는 암산을 요구하는 고전적인 버그의 원천입니다. 더 나쁜 점은 Date 객체가 잘못된 값을 오류가 아닌 '오버플로우'로 조용히 처리한다는 것입니다. new Date(2023, 0, 32)를 시도해 보세요. 1월 32일에 대해 예외를 던지는 대신 2023년 2월 1일로 넘어가 버리며, 잘못된 데이터를 숨기고 잘못된 날짜가 조용히 전파되도록 허용합니다.
Temporal: 우리가 누려야 할 현대적인 해결책
Date 객체의 오류 시대는 마침내 끝나가고 있습니다. 수십 년 동안 개발자들이 그 변덕스러운 동작과 싸워온 끝에, JavaScript의 공식적이고 현대적인 대체제인 Temporal이 고통을 해결하기 위해 등장했습니다. 이것은 단순한 업그레이드가 아니라, JavaScript 탄생 이후부터 괴롭혀온 핵심 설계 결함을 해결하기 위해 세심하게 설계된 근본적인 패러다임의 전환입니다.
Temporal의 가장 중요한 장점은 불변 객체(immutable objects)를 채택했다는 점입니다. 이러한 설계는 가변적인 Date 객체에서 흔히 발생하는, 디버깅하기 어렵고 조용히 일어나는 부작용을 방지하며, 기존 객체를 변경하는 대신 항상 새로운 인스턴스를 반환하도록 보장합니다. 또한 개발자는 시간대 처리에 대해 명시적이고 명확한 제어권을 갖게 됩니다. 이는 글로벌 정확성을 추구하는 애플리케이션을 오랫동안 괴롭혀온 추측과 예상치 못한 변환 문제를 제거합니다.
불변성 외에도 Temporal은 특정 시간 개념을 정확하게 모델링하도록 설계된 강력하고 정밀한 객체 타입들을 제공합니다. 이제 개발자는 모든 날짜-시간 시나리오를 하나의 과부하된 Date 객체에 억지로 끼워 맞출 필요가 없습니다. Temporal은 다음과 같은 전용 타입을 제공합니다:
Temporal.PlainDate: 날짜나 시간대 정보가 없는 날짜.Temporal.PlainTime: 날짜나 시간대 정보가 없는 시간.Temporal.ZonedDateTime: 시간대와 달력에 연결된 특정 시간의 순간.
이러한 특수 객체들은 기존 Date 객체가 가진 고유한 문제점들과는 대조적으로 비교할 수 없는 명확성과 제어력을 제공합니다. Date 객체의 악명 높은 불일치에 대해 더 자세히 알아보려면 Date - JavaScript | MDN을 참조하세요.
이 글이 마음에 드셨나요? 매일 아침 이런 글을 메일로 받아보세요.
하루 한 통 · 두 번의 클릭으로 구독 취소 · 제3자 추적 없음
오늘 당장 Date의 덫에서 탈출하는 방법
개발자 여러분, 변명은 이제 그만할 때입니다. Temporal은 여전히 Stage 3 제안 단계에 머물러 있지만, tc39/proposal-temporal과 같은 안정적인 폴리필(polyfill)을 통해 오늘날 바로 프로덕션 환경에서 사용할 수 있습니다. 네이티브 브라우저 지원이 보편화될 때까지 강력한 날짜 처리를 미룰 필요가 없습니다. 지금 바로 JavaScript 날짜 및 시간 관리의 미래를 받아들여 훨씬 더 신뢰할 수 있는 애플리케이션을 구축하세요.
날짜에 한 달을 더하는 흔하고 골치 아픈 함정을 고려해 보세요. JavaScript의 내장 Date 객체는 고유의 가변성과 종종 당혹스러운 달력 관련 특이점 때문에 자주 놀랍고 부정확한 결과를 초래합니다. 예를 들어, new Date(2023, 0, 31).setMonth(1)을 사용하여 2023년 1월 31일에 한 달을 더하려고 하면, 예상되는 2월 28일이나 29일이 아닌 2023년 3월 2일로 날짜 객체가 잘못 변형됩니다. 반면 Temporal은 명확성과 예측 가능성을 제공합니다:
```javascript // 이전: 버그가 있는 Date const d = new Date(2023, 0, 31); d.setMonth(d.getMonth() + 1); // 2023년 3월 2일로 변형됨
// 이후: 깔끔한 Temporal const plainDate = Temporal.PlainDate.from('2023-01-31'); const nextMonth = plainDate.add({ months: 1 }); // 정확하게 2023년 2월 28일
이러한 극명한 차이는 Temporal의 불변(immutable) 설계와 예측 가능한 산술 연산을 잘 보여줍니다. 이 API는 숨겨진 함정 없이 달력 오버플로우와 시간대를 일관되게 처리합니다. 네이티브의 부족함을 메우기 위해 불필요한 번들 크기와 복잡성만 더하는, 종종 과도한 서드파티 라이브러리에 대한 의존을 버릴 때입니다. 이 공식적인 미래 표준을 지금 학습하세요. 진정으로 읽기 쉽고 오류가 적으며 오래 지속되도록 설계된 날짜 로직을 작성하여, 10년간 이어진 날짜 관련 골칫거리로부터 코드베이스를 해방시키세요.
자주 묻는 질문(FAQ)
JavaScript에서 new Date('0')은 왜 2000년을 반환하나요?
이는 JavaScript 엔진의 구현마다 다른 일관되지 않은 파싱 규칙 때문입니다. 짧고 모호한 문자열은 명확한 표준에 따라 처리되지 않으며, 이로 인해 '0'이 2000년으로 해석되는 것과 같은 예상치 못한 결과가 발생합니다.
Temporal API란 무엇인가요?
Temporal은 결함이 있는 Date 객체를 완전히 대체하기 위해 설계된 현대적인 내장 JavaScript API입니다. 불변 객체, 명시적인 시간대 처리, 그리고 날짜 및 시간 조작을 위한 예측 가능하고 강력한 도구 세트를 제공합니다.
Temporal API는 프로덕션 환경에서 사용할 준비가 되었나요?
TC39 Stage 3 제안인 Temporal API는 안정적이지만 아직 모든 브라우저에서 기본적으로 사용할 수는 없습니다. 개발자들은 공식 폴리필(polyfills)을 통해 오늘날 바로 사용할 수 있으며, 이를 통해 미래 지향적인 코드를 작성하고 즉각적인 이점을 누릴 수 있습니다.
Temporal은 Day.js나 date-fns와 같은 라이브러리보다 어떤 점이 더 나은가요?
Day.js와 같은 라이브러리는 훌륭한 해결책을 제공하지만, 애플리케이션의 번들 크기를 증가시킵니다. Temporal은 JavaScript 언어에 직접 내장된 표준화된 솔루션이 될 것이며, 더 나은 성능을 제공하고 타사 의존성에 대한 필요성을 제거합니다.

