빠른 비교
| 값 | 예시 | 쓰는 경우 |
|---|---|---|
| instant | "2026-05-23T09:30:00Z" | 실제 한 시점을 가리킴 |
| offset time | "2026-05-23T18:30:00+09:00" | 지역 offset을 함께 전달 |
| date-only | "2026-05-23" | 생일, 마감일, 영업일처럼 시간이 없음 |
| epoch milliseconds | 1779509400000 | 내부 처리나 정렬 최적화 |
표현 방식
JSON에는 Date 타입이 없으므로 계약을 별도로 정해야 한다
JSON 값 타입에는 날짜와 시간이 없다. 날짜는 string이나 number로 인코딩해야 하고, 수신자는 그 값이 어떤 규칙을 따른다는 별도 계약을 알아야 한다. createdAt, birthday, expiresAt처럼 이름만 보고 충분하다고 생각하면 timezone, 정밀도, date-only 여부에서 해석이 갈린다.
{
"createdAt": "2026-05-23T09:30:00Z",
"birthday": "1995-08-12",
"expiresAt": "2026-05-23T18:30:00+09:00"
}실제 한 시점은 RFC 3339 date-time string이 기본 선택이다
API 응답에서 생성 시각, 만료 시각, 결제 시각처럼 실제 한 instant를 표현할 때는 RFC 3339 형태의 date-time string이 가장 읽기 쉽고 상호운용성이 좋다. Z는 UTC를 의미하고, +09:00 같은 offset을 붙이면 지역 offset이 포함된다. 시간대 정보를 생략한 문자열은 수신자가 로컬 시간으로 해석할 수 있으므로 공개 API 계약에는 부적합하다.
date-only 값과 timestamp 값은 섞으면 안 된다
생일, 영업일, 마감일처럼 하루 자체가 의미인 값은 "2026-05-23" 같은 date-only string이 맞다. 이를 임의로 "2026-05-23T00:00:00Z"로 바꾸면 timezone 변환 과정에서 전날이나 다음날로 보이는 문제가 생긴다. 반대로 로그 시각이나 만료 시각은 date-only로 표현하면 어느 순간인지 알 수 없다.
epoch number는 단위와 정밀도를 반드시 붙여야 한다
epoch를 number로 쓰면 정렬과 계산은 편하지만, seconds인지 milliseconds인지 바로 알 수 없다. 또한 큰 millisecond timestamp는 언어에 따라 정밀도와 정수 범위 문제를 만날 수 있다. number를 쓴다면 field 이름에 단위를 넣거나 schema와 문서에서 단위를 고정해야 한다.
선택 기준
| 상황 | 적합한 표현 |
|---|---|
| 공개 API의 생성·수정 시각 | RFC 3339 date-time string |
| 사용자 생일과 영업일 | date-only string |
| 내부 로그 정렬 | epoch milliseconds 또는 nanoseconds, 단위 명시 |
| timezone 표시가 중요 | offset 포함 string |
| JSON Schema 검증 | format: "date-time" 또는 format: "date" |
공식 참고: RFC 3339, JSON Schema defined formats
주의할 점
timezone 없는 "2026-05-23T09:30:00"은 수신 환경에 따라 다른 시각으로 해석될 수
있습니다. 공개 API에서는 Z 또는 명시적 offset을 붙이고, date-only 값은 timestamp로
강제로 바꾸지 않는 편이 안전합니다.
{
"expiresAt": "2026-05-23T09:30:00",
"birthday": "1995-08-12T00:00:00Z"
}첫 번째 값은 timezone이 빠져 있고, 두 번째 값은 date-only 의미를 instant처럼 표현한다. 두 경우 모두 소비자 해석이 흔들릴 수 있다.
참고 링크
2 sources