개발 이야기3분 읽기

한 순간이 시스템을 지나며 갖는 열한 가지 모습

기준 시각이 넷입니다. 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로 두는 부동소수점이라, 시각 정밀도가 날짜에 따라 달라집니다. 큰 날짜일수록 표현 가능한 최소 간격이 커집니다.

확인 순서

  1. 낯선 큰 숫자를 만나면 자릿수를 봅니다. 10자리 초, 13자리 밀리초, 18자리는 FILETIME이나 UUID v1입니다
  2. 18자리라면 두 상수를 다 넣어 보고 그럴듯한 쪽을 고릅니다
  3. Excel에서 온 날짜는 1900-03-01 이전인지 확인합니다
  4. 초 단위로 저장된 값을 밀리초로 옮길 때 정밀도가 이미 없다는 것을 감안합니다
  5. 한 번만 실행할 일에는 cron을 쓰지 않습니다

tools.onuel.devEpoch 변환은 초·밀리초와 사람이 읽는 형식 사이를 오가고, 여러 값을 한꺼번에 처리할 때는 Epoch 일괄 변환을 씁니다. 지역이 걸리면 시간대 변환기에서 그 날짜에 실제 적용된 오프셋을 보고, 되풀이 패턴은 cron 표현식에서 읽습니다. 정렬 가능한 식별자는 ULIDUUID v7입니다.

  • #타임스탬프
  • #시간
  • #변환