Temporal API — JavaScript Date의 30년 묵은 저주가 풀린다

9 min read
TemporalJavaScriptChromeDateTC39
Temporal API — JavaScript Date의 30년 묵은 저주가 풀린다

JavaScript의 Date 객체는 1995년에 Java의 java.util.Date를 10일 만에 복사해서 만들었다. 원본인 Java 쪽은 이미 1997년에 deprecated 처리하고 Calendar 클래스로 교체했는데, JavaScript 쪽은 30년이 지난 지금까지 그대로다. Chrome 144가 드디어 이 저주를 풀었다. Temporal API를 정식 탑재한 첫 번째 안정 버전 브라우저가 된 것이다.

Date의 뭐가 문제인가

Date의 문제는 하나가 아니라 구조적 결함의 묶음이다.

문제구체적 사례
Mutabledate.setMonth(1)을 호출하면 원본이 변경된다
타임존 암묵 변환new Date('2026-02-17') → 로컬 타임존 기준으로 해석될 수도, UTC로 해석될 수도 있다
월 인덱스 0-기반1월이 0, 12월이 11. 실수의 온상이다
파싱 비일관성같은 문자열이 브라우저마다 다른 날짜로 파싱된다
캘린더 시스템 부재ISO 8601 외의 달력(음력, 이슬람력 등)을 지원하지 않는다

비유하면 Date는 30년 전에 급하게 만든 임시 다리인데, 그 위로 전 세계 트래픽이 달리고 있는 상황이다. 다리 자체를 교체하려면 모든 차량을 세워야 하니까 아무도 손대지 못하고, 대신 moment.js, date-fns, Day.js, Luxon 같은 우회 도로를 만들어 써왔다.

[💡 잠깐! 이 용어는?] TC39: JavaScript(ECMAScript) 언어 표준을 관리하는 기술 위원회다. 새로운 기능은 Stage 0(아이디어)부터 Stage 4(완료)까지 단계를 거쳐 표준에 포함된다. Temporal은 현재 Stage 3이다.


Temporal이 해결하는 것

Temporal은 Date를 대체하기 위해 설계된 완전히 새로운 날짜/시간 API다. 기존 Date를 수정하는 게 아니라 Temporal이라는 새 네임스페이스 아래에 독립적으로 존재한다.

핵심 원칙 3가지

  1. 불변성(Immutable): 모든 연산이 새 객체를 반환한다. 원본은 절대 변경되지 않는다.
  2. 명시적 타임존: 타임존이 자동으로 끼어드는 일이 없다. 개발자가 직접 지정해야 한다.
  3. 다중 캘린더: ISO 8601, 일본력, 이슬람력 등 다양한 캘린더 시스템을 네이티브로 지원한다.

주요 타입

Temporal은 용도에 따라 여러 타입으로 분리되어 있다. Date 하나로 모든 걸 처리하려다 꼬였던 문제를 근본적으로 해결한 것이다.

타입용도예시
PlainDate날짜만 (타임존 없음)생년월일, 공휴일
PlainTime시간만 (타임존 없음)알람, 일정 시작 시각
PlainDateTime날짜+시간 (타임존 없음)로컬 일정
ZonedDateTime날짜+시간+타임존국제 회의, 항공편
InstantUTC 타임스탬프로그, 타임스탬프 비교
Duration시간 간격"3시간 30분", "P2Y3M"

비유하면 Date가 만능 드라이버 하나로 모든 나사를 돌리려 했다면, Temporal십자, 일자, 별, 육각 드라이버를 세트로 갖춘 공구함이다.


코드로 보는 차이

타임존 없는 순수 날짜

temporal-plain-date.js
const start = Temporal.PlainDate.from('2026-02-13');
const end = start.add({ days: 7 });
 
console.log(end.toString()); // "2026-02-20"
console.log(start.toString()); // "2026-02-13" — 원본 불변

Date였다면 setDate()를 호출하는 순간 원본이 변경됐을 것이다. Temporaladd(), subtract() 모두 새 객체를 반환한다.

명시적 타임존 처리

temporal-zoned-datetime.js
const london = Temporal.Now.zonedDateTimeISO('Europe/London');
const seoul = london.withTimeZone('Asia/Seoul');
 
console.log(london.toString());
// "2026-02-17T09:00:00+00:00[Europe/London]"
console.log(seoul.toString());
// "2026-02-17T18:00:00+09:00[Asia/Seoul]"

타임존이 문자열에 명시적으로 포함된다. Date처럼 "이게 UTC야? 로컬이야?" 하고 추측할 필요가 없다.

[💡 잠깐! 이 용어는?] IANA 타임존: Asia/Seoul, America/New_York 같은 형식의 공식 타임존 식별자다. Temporal은 UTC 오프셋(+09:00)이 아니라 IANA 타임존 이름을 기본으로 사용해서 서머타임 전환도 자동 처리한다.

Duration 비교

temporal-duration.js
const meeting = Temporal.Duration.from({ hours: 1, minutes: 30 });
const lunch = Temporal.Duration.from({ minutes: 45 });
 
const comparison = Temporal.Duration.compare(meeting, lunch);
console.log(comparison); // 1 (meeting이 더 길다)
 
const total = meeting.add(lunch);
console.log(total.toString()); // "PT2H15M"

Date로 시간 간격을 계산하려면 밀리초 뺄셈을 하고 직접 시/분/초로 변환해야 했다. Duration은 이 과정을 타입 레벨에서 지원한다.


브라우저 지원 현황

브라우저상태
Chrome 144정식 지원 (2026년 2월)
Firefox개발 중
Safari미지원
Node.js미지원 (polyfill 필요)

솔직히 프로덕션에서 바로 쓰기는 이르다. Safari와 Firefox 지원이 빠져 있어서 크로스 브라우저 호환이 안 된다. 하지만 Interop 2026 조사 영역에는 포함되지 않았더라도, TC39 Stage 3 제안이 Chrome에 정식 탑재된 것 자체가 다른 브라우저 벤더에게 강력한 신호다.

당장 크로스 브라우저가 필요하다면 @js-temporal/polyfill을 사용할 수 있다. 단, polyfill 번들 크기가 약 60KB (gzip 기준 16KB) 정도이므로 번들 사이즈에 민감한 프로젝트에서는 부분 import 전략을 고려해야 한다.


date-fns, Day.js는 이제 필요 없나

결론부터 말하면, 아직은 필요하다. Temporal이 모든 브라우저에서 동작할 때까지 기존 라이브러리는 여전히 실전 도구다. 하지만 장기적으로는 이들 라이브러리가 Temporal 위의 편의 래퍼(convenience wrapper) 역할로 전환될 가능성이 높다. Temporal이 저수준 기반을 담당하고, 라이브러리가 포매팅이나 로케일 처리 같은 고수준 편의 기능을 제공하는 구조다.

시점권장 전략
지금 (2026 Q1)date-fns / Day.js 유지, Temporal은 학습·실험
2026 하반기Safari/Firefox 지원 확인 후 점진 도입
2027 이후Temporal 네이티브 + 필요시 편의 래퍼

정리

  • Temporal은 JavaScript Date의 30년 된 구조적 결함을 근본부터 교체하는 새 API다
  • 불변성, 명시적 타임존, 다중 캘린더가 핵심 설계 원칙이다
  • Chrome 144가 첫 정식 지원 브라우저이며, 다른 브라우저는 아직 지원하지 않는다
  • 프로덕션 도입은 시기상조이지만, 지금 API에 익숙해지는 것이 최선의 준비다

참고:

관심 있을 만한 포스트

Error.isError() — realm을 넘나드는 안전한 에러 검사 API

instanceof Error가 iframe과 worker에서 실패하는 이유, 그리고 이를 근본적으로 해결하는 Error.isError()의 동작 원리를 정리한다.

JavaScriptError.isError

V8 Explicit Compile Hints — 주석 한 줄로 JavaScript 시작 속도를 630ms 줄이는 법

Chrome 136에 도입된 V8의 Explicit Compile Hints 기능으로 JavaScript 초기 로딩 성능을 개선하는 원리와 사용법을 분석한다.

V8성능 최적화

JavaScript using 키워드 — try/finally 없이 리소스를 자동으로 정리하는 법

TC39 Stage 4에 도달한 Explicit Resource Management 제안을 통해 using 키워드와 Symbol.dispose의 동작 원리를 살펴본다.

JavaScriptTC39

Native JSON Modules — 번들러 없이 JSON을 import하는 시대

Import Attributes와 함께 표준이 된 native JSON module. 어떻게 동작하고, 기존 번들러 방식과 뭐가 다른지 정리했다.

JavaScriptESM

Babel 7.29.0 — 10년 역사의 마지막 마이너, 그리고 8 RC1

2026년 1월 31일, Babel 7의 마지막 마이너 릴리스가 공개됐다. 이 버전이 갖는 역사적 의미와 Babel 8 RC1의 핵심 변화를 정리한다.

BabelJavaScript

V8의 Sea of Nodes 탈출기 — 왜 우아한 이론이 실전에서 무너졌는가

V8 팀이 10년간 사용한 Sea of Nodes IR을 포기하고 Turboshaft로 전환한 7가지 이유와 그 교훈을 정리한다.

V8컴파일러

jQuery 4.0 — 10년 만의 메이저 릴리스, 무엇이 바뀌었나

jQuery가 20주년을 맞아 10년 만에 메이저 버전을 출시했다. IE 지원 축소, ES 모듈 전환, Trusted Types 등 핵심 변경 사항을 정리한다.

jQueryJavaScript

V8 Mutable Heap Numbers — 숫자 하나 바꿀 때마다 새 객체를 만들던 비효율을 잡다

V8 엔진이 스크립트 컨텍스트의 숫자 변수를 매번 새 HeapNumber로 할당하던 방식을 제자리 수정(mutable)으로 바꿔 최대 2.5배 성능 향상을 달성했다.

V8JavaScript