본문으로 건너뛰기
ZEKILO Dev
변환

Unix 시간 초·밀리초 구분법과 2038년 문제

2026.10.03 업데이트 · 6분 읽기

Unix 시간은 1970년부터 센 초이고 시간대가 없습니다. 자릿수로 초와 밀리초를 구분하는 법, 한국 시간으로 바꿀 때의 함정, 32비트 정수가 넘치는 2038년 문제와 점검할 곳을 정리했습니다.

Unix 타임스탬프 변환 바로 사용하기

Unix 시간은 1970-01-01T00:00:00Z부터 센 초이고, 시간대가 없습니다. 지금 시점의 값은 10자리면 초, 13자리면 밀리초이며, 이 둘을 섞는 것이 가장 흔한 타임스탬프 버그입니다. 2038년 문제는 초를 부호 있는 32비트 정수에 담는 곳에만 해당하고, 그 한계는 2038-01-19T03:14:07Z입니다. 값을 Unix 타임스탬프 변환에 붙여 넣으면 어떤 단위로 읽었는지와 UTC·한국 시간 날짜를 바로 볼 수 있습니다.

초·밀리초·마이크로초·나노초

같은 순간(2026-01-01T00:00:00Z)을 네 단위로 적으면 다음과 같습니다.

단위 값 자릿수 만나는 곳
초 1767225600 10 POSIX time(), JWT의 exp·iat
밀리초 1767225600000 13 JavaScript Date.now()
마이크로초 1767225600000000 16 마이크로초 정밀도의 로그·DB
나노초 1767225600000000000 19 트레이싱, 고해상도 시계

초 단위 값은 2001-09-09T01:46:40Z부터 2286-11-20T17:46:39Z까지 10자리이므로 자릿수로 구분할 수 있습니다. 도구의 자동 판별도 같은 원리입니다. 절댓값이 10^11보다 작으면 초, 10^14보다 작으면 밀리초, 10^17보다 작으면 마이크로초, 그 이상은 나노초로 읽고 어떤 단위로 해석했는지 배지로 보여 줍니다. 그래서 1767225600123은 밀리초로 읽혀 2026-01-01T00:00:00.123Z가 됩니다.

단위를 섞으면 알아보기 쉬운 결과가 나옵니다.

상황 결과
초 1767225600을 밀리초로 읽음 1970-01-21T10:53:45.600Z
밀리초 1767225600000을 초로 읽음 서기 57971년의 날짜

날짜가 1970년 1월로 나온다면 밀리초를 받는 곳에 초를 넘긴 경우가 대부분입니다. JavaScript에서 new Date(1767225600)은 1970년 1월이고, new Date(1767225600 * 1000)이 의도한 날짜입니다. 반대로 RFC 7519는 JWT의 exp·iat를 초로 정의하므로 Date.now()가 아니라 Math.floor(Date.now() / 1000)과 비교해야 합니다. 이 클레임은 JWT 디코더에서 날짜로 확인할 수 있습니다.

나노초 값은 JavaScript에서 한 가지를 더 조심해야 합니다. Number가 빠짐없이 정확히 표현하는 정수(안전한 정수)는 9,007,199,254,740,991까지인데 위 나노초 값은 이보다 큽니다. Number('1767225600000000001')은 1767225600000000000이 되어 끝자리를 잃습니다. 문자열이나 BigInt로 다루세요.

Unix 시간에는 시간대가 없습니다

POSIX는 기준 시점(Epoch)을 1970-01-01 00:00:00 UTC로 정의합니다. 그래서 타임스탬프 하나는 어디서나 같은 숫자이고, 시간대는 사람이 읽는 날짜로 바꿀 때만 개입합니다.

1767225600  =  2026-01-01T00:00:00Z     UTC
            =  2026-01-01 09:00:00      한국 시간(KST, UTC+9)

반대로 2026-01-01 09:00:00을 Asia/Seoul 시간대로 변환하면 1767225600으로 돌아옵니다.

흔한 함정은 오프셋이 없는 날짜 문자열입니다. ECMA-262는 UTC 오프셋이 없을 때 날짜만 있는 형식은 UTC로, 날짜와 시간이 있는 형식은 현지 시간으로 해석한다고 정합니다. 시간대가 Asia/Seoul인 컴퓨터에서 실행하면 이렇게 됩니다.

Date.parse('2026-01-01')             →  1767225600000   UTC로 해석
Date.parse('2026-01-01T00:00:00')    →  1767193200000   현지 시간으로 해석(9시간 이른 시점)
Date.parse('2026-01-01T00:00:00Z')   →  1767225600000   UTC 명시

같은 코드가 UTC로 설정된 서버에서는 다른 숫자를 냅니다. 문자열에는 항상 Z나 +09:00 같은 오프셋을 붙이세요. RFC 3339 형식은 오프셋을 필수로 요구합니다.

정의에서 따라 나오는 성질이 하나 더 있습니다. POSIX는 하루를 정확히 86,400초로 계산한다고 정하므로 Unix 시간은 윤초를 세지 않으며, ECMAScript도 같은 방식을 씁니다.

2038년 문제

부호 있는 32비트 정수의 최댓값은 2,147,483,647입니다. 이 값을 초로 읽으면 다음과 같습니다.

 2147483647  →  2038-01-19T03:14:07Z   (한국 시간 12:14:07)
-2147483648  →  1901-12-13T20:45:52Z   1초 뒤 값이 넘쳐 돌아가는 곳

초를 부호 있는 32비트에 담는 소프트웨어는 그 순간 1901년으로 돌아가거나 오류를 낼 수 있습니다. 영향을 받는지는 값을 어디에 담느냐에 달려 있습니다.

저장 방식 표현할 수 있는 마지막 시각
부호 있는 32비트 초 2038-01-19T03:14:07Z
부호 없는 32비트 초 2106-02-07T06:28:15Z
부호 있는 64비트 초 1970년부터 약 2,920억 년
JavaScript Date(밀리초) 275760-09-13T00:00:00Z (±8,640,000,000,000,000 ms)
MySQL TIMESTAMP 컬럼(MySQL 8.4 매뉴얼) ‘2038-01-19 03:14:07’ UTC

문제는 2038년에야 시작되는 것이 아닙니다. 한계를 넘는 미래 날짜를 계산하는 코드는 지금도 걸립니다. 1767225600에 365일짜리 15년을 더하면 2240265600(2040-12-28T00:00:00Z)이 되어 부호 있는 32비트에 들어가지 않습니다. 만료일, 구독 기간, 인증서 유효 기간이 대표적입니다.

점검할 곳은 다음과 같습니다.

  • 초를 담는 정수 컬럼: 부호 있는 32비트 INT는 한계가 같습니다. 64비트 정수 타입을 쓰세요.
  • MySQL TIMESTAMP: 매뉴얼의 범위는 ‘1970-01-01 00:00:01’ UTC부터 ‘2038-01-19 03:14:07’ UTC까지이고, DATETIME은 ’1000-01-01 00:00:00’부터 ’9999-12-31 23:59:59’까지입니다. TIMESTAMP는 저장할 때 UTC로 변환하고 DATETIME은 변환하지 않으므로, 타입을 바꾸면 시간대 동작도 달라집니다.
  • 32비트 빌드와 바이너리 형식: 32비트 time_t, 시간 필드가 32비트로 고정된 파일 형식과 프로토콜.

ZEKILO Dev로 변환하기

  1. Unix 타임스탬프 변환에 숫자를 붙여 넣습니다. 단위는 자동으로 판별하고, 초·밀리초·마이크로초·나노초로 직접 정할 수도 있습니다.
  2. 결과는 ISO 8601(UTC), RFC 2822, 한국어 날짜 표기, 상대 시간으로 나옵니다. 브라우저 시간대와 UTC·KST·JST가 함께 표시되고, 다른 시간대는 IANA 이름으로 고릅니다.
  3. 날짜를 타임스탬프로 바꿀 때는 ISO 8601, YYYY-MM-DD HH:mm:ss(선택한 시간대 적용), RFC 2822 형식으로 입력합니다.

2147483647부터는 32비트 time_t 한계에 관한 안내가 함께 표시됩니다. 모든 계산은 브라우저 안에서 이루어집니다.

정리

  • Unix 시간은 1970-01-01T00:00:00Z부터 센 초입니다. 시간대가 없고 윤초를 세지 않습니다.
  • 지금 날짜라면 10자리는 초, 13자리는 밀리초, 16자리는 마이크로초, 19자리는 나노초입니다.
  • 날짜가 1970년 1월로 나오면 초를 밀리초로 읽은 것입니다.
  • 저장은 UTC 기준 64비트 정수나 Z가 붙은 문자열로 하고, 한국 시간 변환은 표시할 때만 합니다.
  • 부호 있는 32비트 초는 2038-01-19T03:14:07Z에 끝납니다. INT와 MySQL TIMESTAMP 컬럼을 확인하세요.

이 글과 관련된 도구

출처와 기준

다른 가이드