JSON에서 타임스탬프는 어떤 형식인가
핵심 요약: Epoch 숫자와 ISO 문자열은 각자 절충이 있지만, 실제로 깨뜨리는 것은 둘을 섞는 것입니다. 오프셋이 있는 ISO 8601을 쓰고, UTC로 저장하며, 사용자 시간대로 렌더하세요.

핵심부터 말하면, 전송로에는 명시적 오프셋이 있는 ISO 8601을 쓰고, Z가 붙은 UTC로 저장하며, 표시 시점에서만 변환하세요. Epoch 숫자를 고른다면 초와 밀리초를 전역으로 고정하고 필드 이름에 단위를 넣으세요.
2026-10-30 14:30:00이 부족한 이유
그 문자열은 존을 담지 않습니다. 상하이의 14:30과 런던의 14:30은 여덟 시간 차이고 어느 것을 뜻하는지 알 방법이 없습니다. new Date('2026-10-30 14:30:00')은 런타임 로컬 존에서 파싱되어 서버와 브라우저가 한 페이로드에서 다른 시점을 도출합니다. 절대 재현되지 않는 종류의 버그입니다.
맨 2026-10-30은 시점이 전혀 아닙니다. 생일과 청구 기간에는 괜찮고 생성 시간에는 틀립니다.
두 가지 쓸 만한 형식
ISO 8601 문자열
{
"createdAt": "2026-10-30T14:30:00+08:00",
"updatedAt": "2026-10-30T06:30:00Z"
}
읽히고, 형식이 일관되면 정렬 가능하며, 필요하면 밀리초 정밀도가 있고, 자기 서술적입니다.
Epoch 숫자
{ "createdAt": 1793519400 }
간결하고 모호함이 없지만 읽기 어렵고, 초 대 밀리초는 영구적 위험입니다. Epoch를 고르면 단위를 표준화하고 필드 이름에 넣으세요. createdAtMs가 createdAt보다 훨씬 안전합니다.
미리 고정할 만한 관례
| 항목 | 관례 |
|---|---|
| 전송 형식 | Z나 +08:00이 있는 ISO 8601 |
| 저장 시간대 | UTC, DST가 끼어들지 않게 |
| 정밀도 | 밀리초면 충분 |
| 필드 이름 | createdAt, updatedAt, expiresAt |
| 순수 날짜 | 별도 date 필드, 예: birthday: "1990-01-01" |
| 기간 | 정수 + 단위, 예: timeoutMs: 3000 |
렌더링
new Intl.DateTimeFormat('en-GB', {
dateStyle: 'medium',
timeStyle: 'short',
timeZone: 'Europe/London',
}).format(new Date('2026-10-30T06:30:00Z'));
표시가 장치를 따르면 안 될 때는 timeZone을 명시하세요. 브라우저 기본에 의존하는 것은 사용자 대상 시간에는 올바르고 리포트에는 틀립니다.
반복되는 세 버그
맨 날짜가 UTC 자정으로 파싱됨. ECMAScript 명세에 따라 날짜만 있는 문자열은 UTC이고 날짜-시간 문자열은 로컬입니다. 그 불일치가 하루 오차 버그의 신뢰할 만한 원천입니다.
데이터베이스 존이 직렬화기와 불일치. MySQL datetime은 존이 없어 로컬로 쓰고 UTC로 읽으면 모든 것이 오프셋만큼 밀립니다.
일광 절약 시간. 앞으로의 로컬 시간을 저장하면 존재하지 않거나 두 번 발생하는 시점을 만듭니다. UTC에는 그런 간극이 없습니다.
FAQ
ISO 8601과 Epoch 숫자 중 어떻게 고르나?
사람이 페이로드를 읽거나, 사전식 정렬 순서를 원하거나, 값이 자체 존을 담아야 하면 ISO 8601을 쓰세요. 비용은 대략 십여 바이트와 파싱 라이브러리입니다. 간결성과 간단한 언어 간 처리가 더 중요하면 Epoch 숫자를 쓰되 초와 밀리초를 전역으로 고정하고 필드가 어느 단위인지 밝히세요.
맨 날짜와 타임스탬프가 같은 필드를 공유해야 하나?
아니요. 맨 2026-10-30은 시간과 존이 없는 달력 날짜이고, 타임스탬프 필드는 정확한 시점을 담아야 합니다. 생일과 청구 기간은 별도 date 필드에, 생성이나 수정 시간은 ISO 8601 At 필드를 쓰세요.