1P by GN⁺ 2시간전 | ★ favorite | 댓글 1개
  • JavaScript의 기존 Date 객체의 불완전성과 비일관성을 지적하며, 이를 대체할 Temporal API의 등장을 소개
  • Date는 가변 객체(mutable object) 로 동작해 실제 날짜 개념과 어긋나며, 파싱 오류·시간대 처리 한계 등 구조적 문제가 있음
  • Temporal은 불변성 기반의 새로운 날짜·시간 처리 모델을 제공하며, PlainDate, ZonedDateTime, Duration 등 세분화된 클래스 포함
  • Temporal의 메서드는 기존 객체를 수정하지 않고 새로운 객체를 반환, 명확하고 안전한 체이닝 연산 가능
  • Temporal은 현재 표준화 단계 3(Stage 3) 에 있으며, Chrome과 Firefox 등 최신 브라우저에서 실험적으로 지원 중

JavaScript의 Date 객체 문제점

  • Date 생성자는 불일치한 파싱 규칙비직관적 인덱싱으로 혼란을 초래
    • 예: 월(month)은 0부터 시작하지만, 일(day)과 연도(year)는 1부터 시작
    • 문자열 "99"는 1999년으로, "100"은 0100년으로 해석되는 등 일관성 결여
  • Date시간(time) 을 중심으로 설계되어 있으며, 내부적으로 Unix 타임스탬프(밀리초 단위) 로 저장
  • 시간대(time zone) 지원이 제한적이며, 서머타임(DST) 이나 비그레고리력을 인식하지 못함
  • 이러한 한계로 인해 Moment.js, date-fns 등 대형 서드파티 라이브러리 의존이 일반적이며, 이는 성능 저하로 이어짐

불변성과 참조 개념의 충돌

  • JavaScript의 원시값(primitive) 은 불변이며 값 자체로 저장되지만, 객체(object) 는 참조(reference)로 저장되어 변경 가능
  • Date생성자(constructor) 를 통해 만들어지는 객체이므로 가변적
    • 예: setMonth()setDate() 호출 시 원본 객체가 직접 변경됨
  • 이로 인해 동일한 객체를 참조하는 변수 간에 예상치 못한 값 변경이 발생
    • 예: today를 인자로 전달한 함수가 내부에서 날짜를 수정하면, 원본 today도 변경됨

Temporal: 새로운 날짜·시간 API

  • Temporal생성자가 아닌 네임스페이스 객체(namespace object) 로, Math와 유사한 구조
    • 주요 구성: PlainDate, PlainDateTime, PlainTime, ZonedDateTime, Duration, Now
  • Temporal.Now는 현재 시점의 다양한 형태를 반환
    • plainDateISO() → ISO 형식의 날짜
    • zonedDateTimeISO() → 시간대 포함 시각
  • Temporal 객체는 명확한 메서드 체계를 제공
    • add({ days: 1 }), subtract({ years: 2 }) 등으로 명시적 단위 연산 수행
    • 기존 객체를 수정하지 않고 새로운 객체를 반환, 불변성 유지

Temporal의 동작 방식과 장점

  • Temporal 객체는 여전히 객체형이지만, 의도된 불변적 사용 패턴을 따름
    • 예: today.add({ days: 1 })는 새로운 날짜 객체를 반환하며, 원본 today는 변경되지 않음
  • Date 대비 간결하고 명확한 구문 제공
    • 예:
      const today = Temporal.Now.plainDateISO();
      console.log(`Tomorrow will be ${ today.add({ days: 1 }) }. Today is ${ today }.`);
      // 결과: Tomorrow will be 2026-01-01. Today is 2025-12-31.
      
  • 시간대 지정, 기간 계산, ISO 포맷 유지 등 현대적 요구에 부합
  • add, subtract, since, until 등 메서드 체이닝으로 복잡한 날짜 계산을 간결하게 표현 가능

표준화 현황과 향후 전망

  • TemporalECMAScript 제안 단계 3(Stage 3) 에 도달, 브라우저 구현이 권장되는 상태
  • ChromeFirefox에서 이미 실험적 지원이 시작되었으며, 다른 브라우저도 도입 예정
  • 개발자들은 현재부터 테스트 및 피드백 제공을 통해 사양 개선에 참여 가능
  • Date는 여전히 존재하겠지만, 향후에는 Temporal이 기본 날짜 처리 방식으로 자리잡을 전망
  • 글은 “1995년에 교체했어야 했지만, 지금이라도 Temporal.Now가 최적의 시점”이라며 마무리

Hacker News 의견들
  • 이 글은 JavaScript의 Date 생성자가 가진 여러 황당한 동작을 다루고 있음
    특히 'YYYY-MM-DD' 형식이 UTC 자정으로 해석되어, 로컬 시간대에서는 하루가 어긋나는 문제를 설명함
    원래 ISO 8601에서는 시간대 지정이 없으면 로컬 시간으로 간주해야 하지만, ES5 스펙 작성 중 실수로 “Z”(UTC)로 처리되었음
    이후 ES2015에서 수정하려 했으나, 수많은 웹사이트가 기존의 잘못된 동작에 의존하고 있어 웹 호환성을 이유로 되돌려졌음
    자세한 내용은 Broken Parser 섹션 참고

    • 'use strict'처럼 'strict datetime' 지시어가 있었다면 좋았을 것 같음
      이렇게 하면 기존 코드와의 비호환성 문제 없이 올바른 동작을 선택적으로 적용할 수 있었을 것임
      혹은 import Date from 'browser:date'처럼 내부 모듈로 수정된 전역 객체를 불러오는 방식도 가능했을 것임
    • 나도 예전에 문자열을 직접 분리해 시간대 없는 날짜 객체를 만들었음
      생일처럼 단순히 날짜만 의미하는 값이 시간대 때문에 바뀌는 건 말이 안 됨
      예전에 Outlook이 생일을 시간대 포함으로 저장해서, 나라를 옮길 때마다 생일이 하루씩 밀렸던 기억이 있음
    • “웹 호환성의 제단에 바쳐졌다”는 표현이 인상적임
      하지만 대안이 있었을까? 예전 IE5 시절처럼 브라우저 버전별 분기 처리를 강제하는 건 더 나빴을 것 같음
    • jsdate.wtf 사이트를 보면 JS Date의 기괴한 동작들을 직접 체험할 수 있음
    • 이런 문제들이 수많은 작은 버그의 근원이 되는 걸 생각하면 웃기면서도 슬픈 일임
  • Rails와 Ruby의 시간 처리 방식을 정말 부러워함
    Time.current.in_time_zone('America/Los_Angeles') + 3.days - 4.months + 1.hour 같은 API는 직관적이고 강력함
    Ruby는 Time 객체를 하나의 일관된 객체로 오버로드해서, 변환이나 캐스팅 고민이 거의 없음
    JS에서도 new Date().add({ days: 1 })처럼 간단히 쓸 수 있다면 얼마나 좋을까 생각함

    • 하지만 “3.days - 4.months + 1.hour” 같은 문법이 좋은가에 대해서는 의문을 제기함
      또한 코어 라이브러리를 오버로드하는 게 정말 좋은 접근인지도 논쟁의 여지가 있음
  • Safari가 아직 Temporal API를 지원하지 않는 게 아쉬움
    내년쯤에는 지원되길 기대함

  • JavaScript의 Date가 가진 문제는 많지만, 객체라는 점 자체는 큰 문제가 아니라고 생각함
    불변 객체였으면 좋았겠지만, 변경 가능한 객체가 변경된다고 놀랄 일은 아님

    • 하지만 다른 코드가 내가 들고 있던 Date 객체를 암묵적으로 변경할 수 있다는 점이 문제임
      가변성의 진짜 위험은 로컬이 아닌 비지역적 변경에서 발생함
  • Temporal API가 윤초(leap second) 정보를 전혀 다루지 않는 게 불편함
    천문 계산용 JS 도구를 만들고 싶은데, UTC 변환에는 윤초 데이터가 필요함
    temporal-tai 같은 우회책은 있지만, 클라이언트 측에서 윤초 파일을 유지해야 해서 번거로움
    SOP(CORS 정책) 때문에 외부 사이트에서 파일을 바로 가져올 수도 없음
    브라우저는 주기적으로 업데이트되는데, 왜 윤초 정보를 내장하지 않는지 의문임

    • SOP가 윤초 파일을 막는다는 건 오해임
      서버에서 Access-Control-Allow-Origin 헤더를 설정하거나 JS 파일 형태로 제공하면 가능함
      다만 브라우저가 자체적으로 윤초 데이터를 포함하고 유지하는 건 비용이 큰 작업일 수 있음
    • “UTC만 다룬다”는 표현은 부정확함
      UTC는 본래 윤초를 포함하는 시간 척도이므로, 실제로는 POSIX 시간만 다루고 있다고 보는 게 맞음
  • 코드 예시에서 "33"이 아니라 "50"부터 1900년대로 처리된다고 해야 함 — 단순한 오타 지적

  • Temporal polyfill을 사용 중인데, 지금까지 아주 만족스러움

    • 다만 크기가 51KB라서 가벼운 편은 아님 (bundlephobia 링크)
      서버나 대형 앱에는 괜찮지만, 작은 앱에는 부담이 될 수 있음
    • moment나 luxon과 비교했을 때 어떤지 궁금하다는 질문도 나옴
  • 글이 이상하게도 Date.now()를 전혀 언급하지 않음
    Temporal과 비교하려면 Date.now()를 기준으로 설명했어야 함
    이 함수는 1970년 1월 1일부터의 밀리초 단위 경과 시간을 반환함
    Temporal이 더 친절한 API이긴 하지만, 근본적으로는 시간의 상대적 거리를 표현하는 것이 목적임

    • 하지만 글에서 언급된 타임스탬프 관련 버그도 존재함
      그렇다면 Date를 거치지 않고 원하는 형식으로 변환하는 방법은 무엇인지 궁금함
  • “daylight savings time”이 아니라 “daylight saving time”이 맞다는 사소하지만 중요한 교정을 남김

  • 지금까지 JS Date가 이렇게 엉망인 줄 몰랐음

    • 더 안타까운 건, 이런 문제들이 1995년부터 이미 명확히 보였다는 점
      그때 조금만 더 신중했다면 수많은 개발자가 이런 함정에 빠지지 않았을 것임