1716345600 이 timestamp 다. 1970 년 1 월 1 일 00:00:00 UTC 부터 17 억 초 뒤. 왜 1970 일까? 왜 단조 증가가 아닐까? 왜 2038 년에 또 한 번 사고가 날 거라고 할까? 이 가이드는 Unix time 의 정의, leap second 의 골치, monotonic vs wall clock 차이, Y2038 문제 정리.
Unix epoch — 왜 1970-01-01?
Unix 의 1 번째 release 가 1971 년. 시스템 시간 자료형이 32-bit signed integer 였고, 단위는 1/60 초:
32-bit signed × 1/60 초 = ±2^31 / 60 / 60 / 60 / 24 / 365 ≈ ±1.13 년
→ 1971 부터 시작하면 1972-08 까지만 표현 가능. 너무 짧음.Unix 4 (1973) 부터 단위를 1 초로 변경:
32-bit signed × 1 초 = ±2^31 초 ≈ ±68.1 년
→ 1970-01-01 기준 ±68 년 → 1902 ~ 2038 년 표현 가능그 시점에 "정확히 언제부터" 가 임의 결정. 1970-01-01 00:00:00 UTC 채택. Unix 시스템 출시 이전이면서 깔끔한 십년 단위.
Unix time = "1970 부터의 초 수" — 그러나 단조 X
교과서 정의 — Unix timestamp = 1970-01-01 UTC 부터 흘러간 초. 그러나 사실:
- 윤초 (leap second) 무시 — Unix time 은 "1 일 = 86,400 초" 강제. 실제 지구 자전 느려지면 가끔 추가되는 윤초를 cleverly 무시.
- 거꾸로 갈 수 있음 — NTP 동기, 사용자 시간 변경, summer time 종료 등.
윤초 — 1972 부터 27 번 추가
지구 자전이 점점 느려져 UT1 (천문) vs TAI (원자) 시간이 어긋남. UTC = TAI + leap seconds 로 보정. 1972 ~ 2017 사이 27 번 추가 (이후 X).
Unix time 의 처리:
정상 자정: 23:59:58 → 23:59:59 → 00:00:00
leap 자정: 23:59:58 → 23:59:59 → 23:59:60 → 00:00:00
↑ 윤초
Unix 시스템 동작:
- 옵션 A (clock 멈춤): 23:59:59 가 2 초 동안 → 단조 OK 지만 시간이
멈춤
- 옵션 B (clock smear): 윤초를 24 시간에 걸쳐 분산 → Google 채택
- 옵션 C (윤초 반복): 23:59:59.5 → 23:59:60.0 → 00:00:00 → 단조 안 됨Cloudflare 가 2017 년 윤초 처리 버그로 일부 서비스 다운. 이후 leap second 폐지 논의가 진행 — 2035 년 시행 예정.
Y2038 — 2038 년 1 월 19 일의 timestamp 사고
2147483647 = 2038-01-19 03:14:07 UTC
2147483648 → -2147483648 (32-bit signed overflow)
= 1901-12-13 20:45:52 UTC32-bit signed Unix time 의 max value 직전. 다음 초에 wrap 되어 1901 년 음수 시간으로.
영향 받는 시스템:
- 오래된 IoT 디바이스 (firmware 못 바꾸는)
- embedded Linux 시스템 — 32-bit ABI
- C 의
time_t가 32-bit 인 곳 - MySQL
TIMESTAMPcolumn (4 byte) — 2038 한계 (DATETIME 은 무관) - UNIX 파일 시스템의 inode (ext2/3 의 mtime/atime 등)
해결 — 64-bit time_t. 모던 시스템은 이미 적용 (2^63 초 = 약 2,920 억 년 표현). 그러나 legacy 코드 / DB schema 가 남아있음. Y2K 처럼 사전 정비 필요.
Wall clock vs Monotonic clock
2 종류의 시계가 OS 에 존재:
Wall clock (system time)
- "진짜" 날짜·시간. NTP 동기로 보정됨.
- 사용자가 변경 가능 (System Preferences 의 시간 설정).
- 윤초 / DST 영향.
- 거꾸로 갈 수 있음.
예 — Node.js Date.now(), Python time.time(), Java System.currentTimeMillis().
Monotonic clock
- OS boot 이후의 단조 증가 카운터.
- NTP / 사용자 변경 영향 X.
- "진짜" 시각 의미 X — 두 timestamp 사이의 경과 시간만 유용.
- 절대 거꾸로 가지 않음.
예 — Node.js performance.now(), Python time.monotonic(), Java System.nanoTime().
언제 무엇
- "지금 몇 시?" / 로그 timestamp / DB 저장 — wall clock
- "이 작업 얼마 걸렸나?" / timeout / 성능 측정 — monotonic
// Bad — wall clock 으로 경과 시간 측정
const start = Date.now();
heavyTask();
const elapsed = Date.now() - start;
// 만약 NTP 가 그 사이 wall clock 을 -5 초 조정하면
// elapsed 가 음수 또는 잘못된 값!
// Good — monotonic
const start = performance.now();
heavyTask();
const elapsed = performance.now() - start;
// 항상 ≥ 0, NTP 영향 0Timezone 의 함정
Unix timestamp 는 timezone-agnostic — 항상 UTC. 표시할 때만 timezone 적용:
Unix time 1716345600
→ UTC: 2024-05-22 00:00:00
→ KST: 2024-05-22 09:00:00 (UTC+9)
→ PST: 2024-05-21 17:00:00 (UTC-7, summer)timezone-pitfalls 가이드 참조.
DST (Daylight Saving Time) 의 함정
Spring forward / fall back 의 1 시간. 한국은 DST X 지만 미국· 유럽 사용자 대상 시스템은:
2024-11-03 (DST 종료) 02:00 미국 동부:
02:00:00 → 01:00:00 (1 시간 뒤로)
이 사이에 03:30 동부 입력이 있으면 어느 1:30 인가? 모호함.해결 — 항상 UTC 저장 + 표시 시점에만 timezone 변환.
해상도 — 초·밀리초·마이크로초·나노초
| 단위 | 일반적 사용 | Unix timestamp |
|---|---|---|
| 초 | Unix, syslog, cron | 1716345600 (10 자리) |
| 밀리초 (ms) | JavaScript Date, Java | 1716345600000 (13 자리) |
| 마이크로초 (μs) | Python time, Postgres | 1716345600000000 (16 자리) |
| 나노초 (ns) | Go time, Linux kernel | 1716345600000000000 (19 자리) |
timestamp 가 13 자리면 ms, 10 자리면 초. 첫 진단으로 길이 확인.
Unix 타임스탬프 변환 가 모든 해상도 자동 인식.
ISO 8601 vs Unix timestamp
시간 표현의 두 진영:
- Unix timestamp — 정수 1 개. 단순, 작음, 비교 쉬움, timezone 없음. 사람이 읽기 어렵.
- ISO 8601 —
2024-05-22T00:00:00Z. 사람 읽기 쉬움, timezone 포함 가능. parsing 부담.
실무 — DB 저장은 timestamp (정수 비교 빠름) 또는 timestamptz (Postgres). API 응답은 ISO 8601 (사람 친화 + timezone 정보).
흔한 함정
1. Date 의 ambiguity
new Date("2024-05-22")
// → 2024-05-22T00:00:00.000Z (UTC 자정)
// 사용자 의도: 로컬 자정? 그러면 다른 timestamp.2. JavaScript 의 month 0-index
new Date(2024, 5, 22) // ← 2024-06-22 (5 = June, not May!)3. timestamp 의 단위 추측
API 응답의 timestamp 가 ms 인지 초인지 모름. 13 자리는 ms, 10 자리는 초. Unix 타임스탬프 변환 가 자동 감지.
4. setTimeout 의 정밀도 한계
setTimeout(cb, 1); // 실제로는 ~4ms 최소
// 모던 브라우저: 1ms (active tab)
// background tab: 1000ms
setInterval 누적 drift — 매번 새 setTimeout 권장5. Date diff 의 month 한계
"1 개월 후" 가 명확하지 않음:
2024-01-31 + 1 month = ?
→ 2024-02-31 (존재 X) → 2024-02-29 (DB 마다 다름) → 2024-03-02날짜 계산기 가 명확한 계산.
참고 자료
- POSIX seconds since epoch — Open Group
- Y2038 problem — Wikipedia
- Leap second history — Wikipedia
- Cloudflare 2017 leap second incident — Cloudflare blog
- ISO 8601 — ISO
요약
- Unix epoch = 1970-01-01 UTC. 32-bit signed 의 ±68 년 표현 한계로 선정.
- Unix time 은 "1 일 = 86,400 초" 가정 → 윤초 무시. 진정한 단조 X.
- Y2038 = 32-bit signed time_t overflow → 2038-01-19. legacy 시스템 정비 필요. 64-bit 가 표준.
- Wall clock (Date.now) vs Monotonic clock (performance.now). 경과 시간 측정은 무조건 monotonic.
- Timezone 은 표시 단계. 저장은 UTC timestamp.
- 해상도 10/13/16/19 자리 = 초/ms/μs/ns. 첫 진단으로 길이 확인.
- 실험 — Unix 타임스탬프 변환 / 날짜 포매터 / 날짜 계산기 / 타임존 변환기.