JavaScript의 Date 객체는 1995년에 Java에서 그대로 복사해 온 것으로, 수많은 함정이 있습니다. 공부하다 보니 "이게 왜 이렇게 동작하지?" 싶은 순간이 정말 많았습니다.

Date의 대표적인 함정들

월(month)이 0부터 시작

JS
// 2026년 3월 28일을 만들려면?
const date = new Date(2026, 2, 28); // 2가 3월!
console.log(date.getMonth()); // 2 — 3월인데 2를 반환

// 0: 1월, 1: 2월, ..., 11: 12월
const months = [
  "1월", "2월", "3월", "4월", "5월", "6월",
  "7월", "8월", "9월", "10월", "11월", "12월",
];
console.log(months[date.getMonth()]); // "3월"

문자열 파싱의 비일관성

JS
// ISO 8601 형식 — UTC로 파싱
new Date("2026-03-28");
// → 2026-03-28T00:00:00.000Z (UTC)

// 슬래시 형식 — 로컬 시간으로 파싱
new Date("2026/03/28");
// → 2026-03-28T00:00:00.000+09:00 (KST)

// 하이픈 vs 슬래시로 다른 결과가 나옴!
const d1 = new Date("2026-03-28");
const d2 = new Date("2026/03/28");
console.log(d1.getTime() === d2.getTime()); // false (한국 기준)

이 차이 때문에 날짜 문자열 파싱은 항상 명시적으로 하는 것이 안전합니다.

잘못된 날짜도 허용

JS
// 2월 30일? → 자동으로 3월로 넘어감
const invalid = new Date(2026, 1, 30);
console.log(invalid); // 2026-03-02 — 에러 없이 보정됨

// 이것을 역이용하면 해당 월의 마지막 날을 구할 수 있음
function getLastDay(year, month) {
  return new Date(year, month, 0).getDate();
}
console.log(getLastDay(2026, 2)); // 28 (2월)
console.log(getLastDay(2024, 2)); // 29 (윤년)

타임존 문제

JS
const now = new Date();

// 로컬 시간
console.log(now.toString());
// "Sat Mar 28 2026 15:30:00 GMT+0900 (한국 표준시)"

// UTC 시간
console.log(now.toISOString());
// "2026-03-28T06:30:00.000Z"

// getHours vs getUTCHours
console.log(now.getHours());    // 15 (로컬)
console.log(now.getUTCHours()); // 6  (UTC)

타임존 변환

JS
// toLocaleString으로 다른 타임존 표시
const now = new Date();

console.log(now.toLocaleString("ko-KR", { timeZone: "Asia/Seoul" }));
// "2026. 3. 28. 오후 3:30:00"

console.log(now.toLocaleString("ko-KR", { timeZone: "America/New_York" }));
// "2026. 3. 28. 오전 1:30:00"

주요 메서드 정리

JS
const date = new Date(2026, 2, 28, 15, 30, 0);

// Getter
date.getFullYear();  // 2026
date.getMonth();     // 2 (3월)
date.getDate();      // 28
date.getDay();       // 6 (토요일, 0=일요일)
date.getHours();     // 15
date.getMinutes();   // 30
date.getTime();      // 밀리초 타임스탬프

// Setter
date.setFullYear(2027);
date.setMonth(0); // 1월로 변경

// 비교
const d1 = new Date("2026-01-01");
const d2 = new Date("2026-12-31");
console.log(d1 < d2);  // true
console.log(d1.getTime() - d2.getTime()); // 밀리초 차이

날짜 계산 패턴

JS
// 날짜 차이 (일수)
function daysBetween(d1, d2) {
  const msPerDay = 24 * 60 * 60 * 1000;
  return Math.round((d2 - d1) / msPerDay);
}

const start = new Date("2026-01-01");
const end = new Date("2026-03-28");
console.log(daysBetween(start, end)); // 86

// N일 후
function addDays(date, days) {
  const result = new Date(date);
  result.setDate(result.getDate() + days);
  return result;
}

console.log(addDays(new Date("2026-03-28"), 7));
// 2026-04-04

날짜 포맷팅

JS
const date = new Date("2026-03-28T15:30:00");

// toLocaleDateString
date.toLocaleDateString("ko-KR"); // "2026. 3. 28."

// 옵션으로 세밀한 제어
date.toLocaleDateString("ko-KR", {
  year: "numeric",
  month: "long",
  day: "numeric",
  weekday: "long",
}); // "2026년 3월 28일 토요일"

// Intl.DateTimeFormat (같은 기능, 재사용 가능)
const formatter = new Intl.DateTimeFormat("ko-KR", {
  dateStyle: "full",
  timeStyle: "short",
});
formatter.format(date); // "2026년 3월 28일 토요일 오후 3:30"

Temporal API — Date의 후계자

Temporal API는 Date의 모든 문제를 해결하기 위해 설계된 새 표준입니다.

JS
// Temporal.PlainDate — 타임존 없는 날짜
const date = Temporal.PlainDate.from("2026-03-28");
console.log(date.month); // 3 — 1부터 시작!
console.log(date.dayOfWeek); // 6 (토요일, 1=월요일)

// 날짜 계산이 직관적
const nextWeek = date.add({ days: 7 });
console.log(nextWeek.toString()); // "2026-04-04"

// 차이 계산
const diff = date.until(nextWeek);
console.log(diff.days); // 7

// Temporal.ZonedDateTime — 타임존 포함
const zdt = Temporal.ZonedDateTime.from({
  timeZone: "Asia/Seoul",
  year: 2026,
  month: 3,
  day: 28,
  hour: 15,
  minute: 30,
});

// Temporal.Instant — 정확한 시점 (UTC)
const instant = Temporal.Now.instant();

Date vs Temporal 비교

기능DateTemporal
월 인덱스0부터 (함정)1부터 (직관적)
불변성가변불변
타임존로컬 + UTC만모든 타임존
날짜만불가 (시간 포함)PlainDate
시간만불가PlainTime
파싱비일관적엄격하고 일관적

실무에서의 선택

JS
// 현재 — date-fns 또는 dayjs 라이브러리 사용 권장
import { format, addDays, differenceInDays } from "date-fns";

format(new Date(), "yyyy-MM-dd"); // "2026-03-28"
addDays(new Date(), 7);
differenceInDays(new Date("2026-12-31"), new Date());

// 미래 — Temporal API가 브라우저에 안착하면 라이브러리 불필요

**기억하기 **: Date의 월은 0부터 시작하고, 문자열 파싱은 형식에 따라 타임존 해석이 달라집니다. 실무에서는 date-fns 같은 라이브러리를 쓰되, Temporal API가 브라우저에 안착하면 전환을 준비하면 됩니다.

댓글 로딩 중...