같은 날짜 문자열이 브라우저마다 다른 시각으로 해석된 이유
문제 발생
API가 준 문자열을 그대로 넘겼는데 표시되는 날짜가 사용자마다 하루씩 어긋났습니다.
new Date("2026-03-01"); // UTC 자정
new Date("2026-03-01T00:00:00"); // 로컬 자정 — 위와 9시간 차이
new Date("2026/03/01 09:00"); // 브라우저마다 결과가 다를 수 있다원인 분석
파싱 규칙이 형식마다 다릅니다. MDN은 두 가지를 분명히 합니다.
첫째, 표준 형식 밖은 보장되지 않습니다 — parse()가 처리할 수 있는 형식은 명시적으로 정해져 있지 않으며, 그 밖의 형식은 구현 정의(implementation-defined)라 모든 브라우저에서 동작하지 않을 수 있습니다. 문서는 이 절이 브라우저나 버전에 따라 달라질 수 있는 구현별 동작을 담고 있으니 코드에 쓰기 전에 직접 테스트하라고까지 적어둡니다.
둘째, 표준 형식 안에서도 함정이 있습니다 — 날짜만 있는 형식은 UTC로 취급되고, 타임존이 없는 날짜-시각 형식은 로컬 시간으로 취급됩니다.
Date.parse("2019-01-01"); // UTC
Date.parse("2019-01-01T00:00:00"); // 로컬 시간
Date.parse("2019-01-01T00:00:00.000Z"); // 명시적 UTC한국(UTC+9)에서는 이 차이가 날짜 한 칸으로 나타납니다. 그래서 "어제 글로 표시된다" 같은 제보로 들어옵니다.
MDN은 이 불안정성이 새 API가 등장한 배경이라고까지 적습니다 — Date.parse()의 신뢰할 수 없음이 Temporal API가 도입된 동기 중 하나라는 것입니다.
해결 방안
- 오프셋을 항상 포함한 ISO 8601로 주고받습니다. 서버·클라이언트·DB 모두 이 규약 하나로 통일하는 게 가장 큰 효과를 냅니다.
2026-03-01T00:00:00.000Z
2026-03-01T09:00:00+09:00-
임의 형식을 파싱하지 않습니다.
"2026/03/01"같은 문자열이 들어오면 파싱하지 말고 거부하거나 명시적으로 변환합니다. 값을 만든 쪽을 고치는 게 맞습니다. -
표시할 때만 지역화합니다. 계산은 UTC 기준으로 하고, 화면에는
Intl.DateTimeFormat으로 타임존을 명시해 그립니다.
new Intl.DateTimeFormat("ko-KR", { timeZone: "Asia/Seoul", dateStyle: "long" }).format(d);-
날짜만 다루는 값은
Date로 만들지 않는 것도 방법입니다. 생일이나 마감일처럼 "시각이 없는 날짜"를Date에 담는 순간 타임존 변환의 대상이 됩니다. 문자열"2026-03-01"그대로 다루거나Temporal.PlainDate를 검토합니다. -
테스트에서 타임존을 바꿔봅니다.
TZ=Asia/Seoul,TZ=UTC로 각각 돌려야 이 종류의 버그가 드러납니다. CI가 UTC라면 로컬에서만 재현되는 문제가 됩니다.
댓글0
댓글을 남기려면 로그인이 필요해요. 로그인
아직 댓글이 없어요. 첫 의견을 편하게 남겨 보세요.