본문으로 건너뛰기
yutils

Unix Timestamp 는 왜 1970 년부터 셀까?

왜 1970 년부터인지, Unix time 이 사실 단조 증가하지 않는 이유, 32-bit 시스템의 Y2038 문제, 윤초 사태, monotonic vs wall clock 차이, 그리고 왜 "지금" 이 거꾸로 갈 수 있는지.

약 8분 읽기

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 UTC

32-bit signed Unix time 의 max value 직전. 다음 초에 wrap 되어 1901 년 음수 시간으로.

영향 받는 시스템:

  • 오래된 IoT 디바이스 (firmware 못 바꾸는)
  • embedded Linux 시스템 — 32-bit ABI
  • C 의 time_t 가 32-bit 인 곳
  • MySQL TIMESTAMP column (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 영향 0

Timezone 의 함정

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, cron1716345600 (10 자리)
밀리초 (ms)JavaScript Date, Java1716345600000 (13 자리)
마이크로초 (μs)Python time, Postgres1716345600000000 (16 자리)
나노초 (ns)Go time, Linux kernel1716345600000000000 (19 자리)

timestamp 가 13 자리면 ms, 10 자리면 초. 첫 진단으로 길이 확인.

Unix 타임스탬프 변환 가 모든 해상도 자동 인식.

ISO 8601 vs Unix timestamp

시간 표현의 두 진영:

  • Unix timestamp — 정수 1 개. 단순, 작음, 비교 쉬움, timezone 없음. 사람이 읽기 어렵.
  • ISO 86012024-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

날짜 계산기 가 명확한 계산.

참고 자료

요약

  • 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 타임스탬프 변환 / 날짜 포매터 / 날짜 계산기 / 타임존 변환기.
가이드 목록으로