한 순간이 시스템을 지나며 갖는 열한 가지 모습
기준 시각이 넷입니다. 1970·1601·1582·1900이 어디서 나오고 무엇을 틀리게 하는지 정리했습니다.
같은 순간 하나를 여러 형식으로 적어 봤습니다.
유닉스 초 1788167730
유닉스 밀리초 1788167730250
ISO 8601 2026-08-31T09:15:30.250Z
ISO 8601 (KST) 2026-08-31T18:15:30+09:00
RFC 2822 (메일) Mon, 31 Aug 2026 09:15:30 GMT
Windows FILETIME 134326413302500000
UUID v1 타임스탬프 140074605302500000
Excel 일련번호 46265.385767
ULID 앞 10자 01M1BHMD2A
UUID v7 앞 48비트 01a0571a-344a-7…
cron 30 15 9 31 8 *
전부 같은 순간입니다. 그런데 숫자가 서로 닮지도 않았습니다.
기준 시각이 넷이다
숫자가 갈리는 이유의 대부분이 이것입니다.
| 형식 | 기준 시각 | 단위 |
|---|---|---|
| 유닉스 | 1970-01-01 | 초 또는 밀리초 |
| Windows FILETIME | 1601-01-01 | 100나노초 |
| UUID v1 | 1582-10-15 | 100나노초 |
| Excel | 1900-01-01 | 일 (소수로 시각) |
1601년은 그레고리력의 400년 주기가 시작하는 해입니다. 윤년 계산이 400년마다 반복되므로 그 경계에 맞춘 것입니다.
1582년 10월 15일은 그레고리력이 처음 시행된 날입니다. UUID 규격이 이 날을 골랐습니다.
변환 상수가 필요합니다.
FILETIME → 유닉스 밀리초 (n / 10000) - 11644473600000
UUID v1 → 유닉스 밀리초 (n / 10000) - 12219292800000
이 두 상수를 헷갈리는 것이 흔한 실수입니다. 차이가 약 18년이라 결과가 그럴듯하게 나와서 눈에 안 띕니다.
Excel에는 없는 날이 있다
Excel 일련번호는 1900-01-01을 1로 셉니다. 그런데 1900년 2월 29일이 존재합니다.
1900년은 윤년이 아닙니다(400으로 나뉘지 않는 100의 배수). Lotus 1-2-3의 버그였는데, 호환성 때문에 Excel이 그대로 물려받았고 지금도 그렇습니다.
이 버그는 변환 상수에 그대로 남아 있습니다. Excel 일련번호를 유닉스 시각으로 옮길 때 쓰는 값이 25569인데, 1900-01-01부터 1970-01-01까지의 실제 날짜 차이는 25,567일입니다.
실제 날짜 차이 25,567일
Excel 오프셋 25,569일
차이 2일
= 1900-01-01 을 0 이 아니라 1 로 세는 것 (+1)
+ 존재하지 않는 1900-02-29 를 하루로 세는 것 (+1)
그래서 1900년 3월 1일 이전 날짜는 하루가 어긋납니다. 그 이후만 계산이 맞고, 대부분의 실무 데이터가 그 이후라 드러나지 않을 뿐입니다.
정렬 가능한 형식은 시각을 앞에 둔다
ULID 01M1BHMD2A + 무작위 16자
UUID v7 앞 48비트가 유닉스 밀리초
UUID v1 타임스탬프의 낮은 자리가 앞
ULID와 UUID v7은 타임스탬프를 문자열 앞에 두어 사전순 정렬이 시간순이 되게 합니다. UUID v1은 낮은 자리를 앞에 두는 바람에 그렇게 되지 않습니다.
즉 같은 순간을 담아도 자리 배치가 정렬 가능 여부를 정합니다.
cron만 순간이 아니다
30 15 9 31 8 *
이 표현은 "2026년 8월 31일 9시 15분 30초"가 아니라 "매년 8월 31일 9시 15분"입니다. 되풀이되는 패턴이지 한 순간이 아닙니다.
그래서 cron에는 연도 필드가 없습니다. 표준 cron은 분·시·일·월·요일 다섯 개이고, 초 필드는 구현에 따라 있거나 없습니다.
한 번만 실행할 일에 cron을 쓰면 매년 다시 실행됩니다.
정밀도가 다르다
유닉스 초 1초
유닉스 밀리초 1밀리초
FILETIME 100나노초
UUID v1 100나노초
Excel 부동소수점이라 하루의 소수부
ISO 8601 적은 만큼
초 단위 타임스탬프로 저장했다가 밀리초로 바꾸면 소수점 아래가 0으로 채워집니다. 잃어버린 정밀도는 돌아오지 않습니다.
Excel은 하루를 1로 두는 부동소수점이라, 시각 정밀도가 날짜에 따라 달라집니다. 큰 날짜일수록 표현 가능한 최소 간격이 커집니다.
확인 순서
- 낯선 큰 숫자를 만나면 자릿수를 봅니다. 10자리 초, 13자리 밀리초, 18자리는 FILETIME이나 UUID v1입니다
- 18자리라면 두 상수를 다 넣어 보고 그럴듯한 쪽을 고릅니다
- Excel에서 온 날짜는 1900-03-01 이전인지 확인합니다
- 초 단위로 저장된 값을 밀리초로 옮길 때 정밀도가 이미 없다는 것을 감안합니다
- 한 번만 실행할 일에는 cron을 쓰지 않습니다
tools.onuel.dev의 Epoch 변환은 초·밀리초와 사람이 읽는 형식 사이를 오가고, 여러 값을 한꺼번에 처리할 때는 Epoch 일괄 변환을 씁니다. 지역이 걸리면 시간대 변환기에서 그 날짜에 실제 적용된 오프셋을 보고, 되풀이 패턴은 cron 표현식에서 읽습니다. 정렬 가능한 식별자는 ULID와 UUID v7입니다.
- #타임스탬프
- #시간
- #변환