
SOFTMOA TECHNOLOGY
Temporal API로 JavaScript 날짜/시간 처리 완전 정복하기
소프트모아가 정리한 기술 기록입니다.
Contents
작성일 2026. 04. 04.
JavaScript 개발자를 오랫동안 괴롭혀온 Date 객체의 시대가 드디어 저물고 있습니다. ES2026에서 정식 도입되는 Temporal API는 불변 객체, 타임존 퍼스트 클래스 지원, 비그레고리력 캘린더 등 현대적인 날짜/시간 처리의 모든 것을 제공합니다. moment.js나 date-fns 같은 라이브러리 없이도 복잡한 날짜 연산을 정확하게 수행할 수 있습니다.
Date 객체의 한계
기존 Date 객체는 1995년 Java의 java.util.Date를 그대로 복사한 것으로, 태생적 결함이 많습니다.
// Date 객체의 문제점들
const date = new Date(2026, 0, 1); // 월이 0부터 시작 (0 = 1월)
date.setMonth(12); // 13월? -> 다음 해 1월로 자동 변환
// 뮤터블 - 원본이 변경됨
const original = new Date('2026-04-04');
const modified = original;
modified.setDate(10);
console.log(original.getDate()); // 10 - 원본도 변경!
// 타임존 처리 불가
// UTC나 로컬 타임존만 지원, 임의 타임존 변환 불가능Temporal API 핵심 타입
Temporal은 용도에 따라 명확하게 구분된 여러 타입을 제공합니다.
Temporal.PlainDate - 날짜만
// 날짜만 다루기 (시간 정보 없음)
const today = Temporal.PlainDate.from('2026-04-04');
const birthday = Temporal.PlainDate.from({ year: 1990, month: 3, day: 15 });
// 불변 - 항상 새 객체 반환
const nextWeek = today.add({ days: 7 });
console.log(today.toString()); // 2026-04-04 (원본 유지)
console.log(nextWeek.toString()); // 2026-04-11
// 날짜 비교
console.log(Temporal.PlainDate.compare(today, nextWeek)); // -1
console.log(today.equals(nextWeek)); // false
// 유용한 속성들
console.log(today.dayOfWeek); // 6 (토요일)
console.log(today.daysInMonth); // 30 (4월)
console.log(today.daysInYear); // 365
console.log(today.weekOfYear); // 14Temporal.PlainTime - 시간만
const lunchTime = Temporal.PlainTime.from('12:30:00');
const meetingEnd = lunchTime.add({ hours: 1, minutes: 30 });
console.log(meetingEnd.toString()); // 14:00:00
// 나노초 정밀도 지원
const precise = Temporal.PlainTime.from('10:30:00.123456789');
console.log(precise.nanosecond); // 789Temporal.PlainDateTime - 날짜 + 시간 (타임존 없음)
const appointment = Temporal.PlainDateTime.from('2026-04-04T14:30:00');
const rescheduled = appointment.add({ hours: 2, days: 1 });
console.log(rescheduled.toString()); // 2026-04-05T16:30:00Temporal.ZonedDateTime - 타임존 포함 완전한 시간
// 타임존 지정 - IANA 타임존 이름 사용
const seoulMeeting = Temporal.ZonedDateTime.from({
year: 2026, month: 4, day: 4,
hour: 14, minute: 0,
timeZone: 'Asia/Seoul'
});
// 다른 타임존으로 변환
const nyTime = seoulMeeting.withTimeZone('America/New_York');
console.log(nyTime.toString());
// 2026-04-04T01:00:00-04:00[America/New_York]
const londonTime = seoulMeeting.withTimeZone('Europe/London');
console.log(londonTime.toString());
// 2026-04-04T06:00:00+01:00[Europe/London]
// DST(서머타임) 자동 처리
const beforeDST = Temporal.ZonedDateTime.from(
'2026-03-08T01:30:00[America/New_York]'
);
const afterAdd = beforeDST.add({ hours: 2 });
// 서머타임 전환을 자동으로 처리기간과 차이 계산
// Temporal.Duration - 기간 표현
const projectDuration = Temporal.Duration.from({
months: 3, weeks: 2, days: 5
});
console.log(projectDuration.total({ unit: 'days' }));
// 두 날짜 사이의 차이
const start = Temporal.PlainDate.from('2026-01-15');
const end = Temporal.PlainDate.from('2026-04-04');
const diff = start.until(end);
console.log(diff.toString()); // P2M17D (2개월 17일)
console.log(diff.months); // 2
console.log(diff.days); // 17
// 가장 큰 단위 지정
const diffInDays = start.until(end, { largestUnit: 'day' });
console.log(diffInDays.days); // 79
// since는 반대 방향
const ago = end.since(start);
console.log(ago.toString()); // P2M17D실전: D-Day 카운터 구현
function getDDay(targetDateStr) {
const today = Temporal.Now.plainDateISO();
const target = Temporal.PlainDate.from(targetDateStr);
const diff = today.until(target, { largestUnit: 'day' });
if (diff.sign === -1) {
return `D+${Math.abs(diff.days)}`;
} else if (diff.days === 0) {
return 'D-Day';
} else {
return `D-${diff.days}`;
}
}
console.log(getDDay('2026-12-25')); // D-265
console.log(getDDay('2026-01-01')); // D+93실전: 글로벌 미팅 스케줄러
function scheduleMeeting(dateTime, hostTimeZone, attendeeTimeZones) {
const meeting = Temporal.ZonedDateTime.from({
...Temporal.PlainDateTime.from(dateTime),
timeZone: hostTimeZone
});
const schedule = attendeeTimeZones.map(tz => {
const local = meeting.withTimeZone(tz);
const hour = local.hour;
const isWorkHours = hour >= 9 && hour < 18;
return {
timezone: tz,
localTime: local.toPlainDateTime().toString().slice(0, 16),
isWorkHours
};
});
return schedule;
}
const result = scheduleMeeting(
'2026-04-04T10:00',
'Asia/Seoul',
['America/New_York', 'Europe/London', 'Asia/Tokyo']
);
console.log(result);
// [
// { timezone: 'America/New_York', localTime: '2026-04-03T21:00', isWorkHours: false },
// { timezone: 'Europe/London', localTime: '2026-04-04T02:00', isWorkHours: false },
// { timezone: 'Asia/Tokyo', localTime: '2026-04-04T10:00', isWorkHours: true }
// ]폴리필 및 마이그레이션
브라우저 네이티브 지원이 완료되기 전에 @js-temporal/polyfill 패키지로 즉시 사용할 수 있습니다.
npm install @js-temporal/polyfill
// 사용
import { Temporal } from '@js-temporal/polyfill';
const now = Temporal.Now.zonedDateTimeISO();Temporal API는 JavaScript의 가장 오래된 약점 중 하나였던 날짜/시간 처리를 완전히 새롭게 재설계한 것입니다. 불변성, 타입 안전성, 타임존 퍼스트 클래스 지원은 모든 JavaScript 개발자가 오래 기다려온 기능입니다. 새 프로젝트에서는 Temporal API를 기본으로 채택하는 것을 강력히 권장합니다.
Share this
FrontEnd
Showing 1 to 10 of 93 entries
