
SOFTMOA TECHNOLOGY
ES2026 Temporal API 완벽 가이드: Date 객체를 대체하는 새로운 표준
소프트모아가 정리한 기술 기록입니다.
Contents
작성일 2026. 04. 05.
JavaScript 개발자라면 누구나 Date 객체의 불편함을 경험했을 것이다. 월이 0부터 시작하는 문제, 타임존 처리의 어려움, 불변성 부재 등 수많은 함정이 있었다. ES2026에서 정식 표준이 된 Temporal API는 이 모든 문제를 근본적으로 해결한다. moment.js나 date-fns 없이도 날짜와 시간을 정확하고 직관적으로 다룰 수 있게 되었다.
Temporal API의 핵심 개념
Temporal은 날짜와 시간을 다루는 여러 타입을 제공하며, 각 타입은 명확한 목적을 가진다. 모든 Temporal 객체는 불변(immutable)이다.
주요 타입 일람
- Temporal.PlainDate - 타임존 없는 날짜 (2026-04-05)
- Temporal.PlainTime - 타임존 없는 시간 (14:30:00)
- Temporal.PlainDateTime - 타임존 없는 날짜+시간
- Temporal.ZonedDateTime - 타임존이 포함된 완전한 날짜+시간
- Temporal.Instant - UTC 기준의 절대 시점 (에포크 나노초)
- Temporal.Duration - 기간 (P1Y2M3DT4H5M6S)
- Temporal.PlainYearMonth - 연월 (2026-04)
- Temporal.PlainMonthDay - 월일 (04-05)
기본 사용법
날짜 생성과 조작
// 현재 날짜 (시스템 타임존 기준)
const today = Temporal.Now.plainDateISO();
console.log(today.toString()); // "2026-04-05"
// 특정 날짜 생성
const date = Temporal.PlainDate.from("2026-04-05");
const date2 = Temporal.PlainDate.from({ year: 2026, month: 4, day: 5 });
// 날짜 연산 (불변 - 새 객체 반환)
const nextWeek = today.add({ days: 7 });
const lastMonth = today.subtract({ months: 1 });
const specificDate = today.with({ day: 1 }); // 이번 달 1일
console.log(nextWeek.toString()); // "2026-04-12"
console.log(lastMonth.toString()); // "2026-03-05"
// 날짜 속성 접근
console.log(today.year); // 2026
console.log(today.month); // 4 (1부터 시작!)
console.log(today.day); // 5
console.log(today.dayOfWeek); // 7 (일요일, ISO 8601 기준)
시간 다루기
// 현재 시간
const now = Temporal.Now.plainTimeISO();
console.log(now.toString()); // "14:30:45.123456789"
// 특정 시간 생성
const time = Temporal.PlainTime.from("09:30:00");
const time2 = Temporal.PlainTime.from({ hour: 9, minute: 30 });
// 시간 연산
const later = time.add({ hours: 2, minutes: 30 });
console.log(later.toString()); // "12:00:00"
// 날짜와 시간 결합
const dateTime = today.toPlainDateTime(time);
console.log(dateTime.toString()); // "2026-04-05T09:30:00"
타임존 처리
Temporal의 가장 큰 강점 중 하나가 바로 명시적이고 정확한 타임존 처리다.
// 타임존이 포함된 날짜+시간
const seoulTime = Temporal.ZonedDateTime.from(
"2026-04-05T14:30:00+09:00[Asia/Seoul]"
);
console.log(seoulTime.toString());
// "2026-04-05T14:30:00+09:00[Asia/Seoul]"
// 타임존 변환
const nyTime = seoulTime.withTimeZone("America/New_York");
console.log(nyTime.toString());
// "2026-04-05T01:30:00-04:00[America/New_York]"
// 현재 시각을 특정 타임존으로
const tokyoNow = Temporal.Now.zonedDateTimeISO("Asia/Tokyo");
const londonNow = Temporal.Now.zonedDateTimeISO("Europe/London");
// Instant: UTC 기준 절대 시점
const instant = Temporal.Now.instant();
console.log(instant.toString()); // "2026-04-05T05:30:00Z"
// Instant에서 특정 타임존의 시각 구하기
const localTime = instant.toZonedDateTimeISO("Asia/Seoul");
기간(Duration)과 날짜 비교
// Duration 생성
const duration = Temporal.Duration.from({ hours: 2, minutes: 30 });
const isoDuration = Temporal.Duration.from("P1Y2M3DT4H5M");
// 두 날짜 사이의 기간 계산
const start = Temporal.PlainDate.from("2026-01-01");
const end = Temporal.PlainDate.from("2026-04-05");
const diff = start.until(end);
console.log(diff.toString()); // "P94D" (94일)
// 더 큰 단위로 표현
const diffLarge = start.until(end, { largestUnit: "month" });
console.log(diffLarge.toString()); // "P3M4D" (3개월 4일)
// 날짜 비교
const dateA = Temporal.PlainDate.from("2026-04-01");
const dateB = Temporal.PlainDate.from("2026-04-05");
console.log(Temporal.PlainDate.compare(dateA, dateB)); // -1
console.log(dateA.equals(dateB)); // false
// since: until의 반대 방향
const sinceStart = end.since(start);
console.log(sinceStart.toString()); // "P94D"
실전 활용 패턴
예약 시스템에서 영업일 계산
function addBusinessDays(startDate, days) {
let current = startDate;
let added = 0;
while (added < days) {
current = current.add({ days: 1 });
// 토요일(6), 일요일(7) 제외
if (current.dayOfWeek <= 5) {
added++;
}
}
return current;
}
const orderDate = Temporal.PlainDate.from("2026-04-05");
const deliveryDate = addBusinessDays(orderDate, 5);
console.log(deliveryDate.toString()); // "2026-04-14" (주말 제외)
반복 일정 생성
function* generateRecurring(start, interval, count) {
let current = start;
for (let i = 0; i < count; i++) {
yield current;
current = current.add(interval);
}
}
// 매주 월요일 회의
const firstMonday = Temporal.PlainDate.from("2026-04-06");
const meetings = [...generateRecurring(
firstMonday,
{ weeks: 1 },
12
)];
meetings.forEach(date => {
console.log(`${date.toString()} (${date.dayOfWeek === 1 ? '월' : '?'})`);
});
글로벌 서비스 시간 표시
function formatMeetingTime(isoString, userTimeZone) {
const meeting = Temporal.Instant.from(isoString);
const local = meeting.toZonedDateTimeISO(userTimeZone);
return {
date: local.toPlainDate().toString(),
time: local.toPlainTime().toString({ smallestUnit: "minute" }),
timeZone: userTimeZone,
offset: local.offset
};
}
const meetingUTC = "2026-04-06T10:00:00Z";
console.log(formatMeetingTime(meetingUTC, "Asia/Seoul"));
// { date: "2026-04-06", time: "19:00", timeZone: "Asia/Seoul", offset: "+09:00" }
console.log(formatMeetingTime(meetingUTC, "America/New_York"));
// { date: "2026-04-06", time: "06:00", timeZone: "America/New_York", offset: "-04:00" }
Date에서 Temporal로 마이그레이션
// 기존 Date 객체를 Temporal로 변환
const legacyDate = new Date("2026-04-05T14:30:00Z");
const instant = Temporal.Instant.fromEpochMilliseconds(legacyDate.getTime());
const zoned = instant.toZonedDateTimeISO("Asia/Seoul");
// Temporal을 Date로 변환 (레거시 호환)
const temporal = Temporal.Instant.from("2026-04-05T05:30:00Z");
const backToDate = new Date(Number(temporal.epochMilliseconds));
브라우저 및 런타임 지원 현황
2026년 4월 기준, Chrome 126+, Firefox 130+, Safari 19+에서 Temporal API를 기본 지원한다. Node.js는 22.x LTS부터 플래그 없이 사용 가능하다. 아직 구 버전 브라우저를 지원해야 한다면 @js-temporal/polyfill 패키지를 활용할 수 있다.
Share this
FrontEnd
Showing 1 to 10 of 94 entries
