Unix 타임스탬프 변환
Unix 타임스탬프를 원하는 시간대의 날짜·시각으로, 날짜·시각을 에포크 값으로 변환합니다.
Unix 타임스탬프란 무엇인가
Unix 타임스탬프 — 에포크 시각, 또는 POSIX 시각이라고도 합니다 — 는 1970년 1월 1일 00:00:00 UTC(Unix 에포크라 불리는 순간)로부터 몇 초가 지났는지 세는 단일 숫자입니다. 시간대도 달력도 서식도 없는 하나의 정수이므로, 시간의 한 순간을 저장·정렬·비교하거나 네트워크로 보내야 할 때 컴퓨터가 손을 뻗는 형식입니다. 데이터베이스의 "created_at" 열, JWT의 "iat"·"exp" 클레임, 파일의 mtime, 그리고 앞으로 읽을 거의 모든 로그 파일의 타임스탬프 뒤에 있는 것이 이것입니다.
대가는 맨 숫자가 사람에게 아무 뜻도 없다는 점입니다. 1716197600은 흠잡을 데 없이 올바른 순간이지만, 그것이 지난 화요일인지 3년 전인지 한눈에 알 수 없습니다. 그 양방향 번역이야말로 이 도구가 하는 일입니다.
초냐 밀리초냐 — 사람을 무는 모호함
본래의 Unix 관례는 정수 초를 세며, 셸의 date +%s, PHP의 time(), 잘라 낸 Python의 time.time()에서 얻는 것이 이것입니다. JavaScript, Java 등 많은 것은 밀리초를 셉니다: Date.now()는 1000배 큰 수를 돌려줍니다. 둘 다 "타임스탬프"라 불리고, 뒤바꾸는 것은 가장 흔한 날짜 버그 중 하나입니다.
그 실패는 요란하지 않고 조용히 일어납니다. 밀리초 값을 초로 읽으면 날짜가 수만 년 앞으로 날아가고, 초 값을 밀리초로 읽으면 모든 것이 1970년 1월로 무너집니다. 어느 쪽도 오류를 내지 않습니다 — 진짜처럼 보이는 잘못된 날짜가 나올 뿐입니다.
이 도구는 수의 크기로 추측하고, 그 추측을 결과 바로 옆에 알립니다. 오늘의 에포크 초는 10자리, 오늘의 에포크 밀리초는 13자리라 추측은 거의 늘 맞습니다 — 하지만 곧 버그 리포트에 붙여넣을 값에는 "거의"로 충분하지 않으므로, 해석은 늘 보이고 늘 클릭 한 번으로 바꿀 수 있습니다.
시간대, UTC, 그리고 "로컬"이 미끄러운 이유
Unix 타임스탬프에는 시간대가 없습니다. 그것은 하나의 순간을 가리키고, 그 같은 순간이 런던에서는 09:33, 예루살렘에서는 11:33, 서울에서는 18:33에 동시에 있습니다. 시간대는 값의 일부가 아니라 값을 들여다보는 렌즈입니다.
그래서 이 도구는 여러 렌즈를 한꺼번에 보여 줍니다. UTC는 모든 서버와 로그가 합의하는 중립 기준입니다. 로컬 시각은 사용자의 기기가 보고하는 것으로, 지역 이름(예: Europe/Berlin)을 붙여 어느 렌즈가 낳은 값인지 늘 알 수 있게 표시합니다 — 판별은 브라우저 안에서 이루어지므로 베를린의 방문자는 베를린 시각을, 서울의 방문자는 서울 시각을 봅니다. 세 번째 줄은 전체 IANA 시간대 데이터베이스에서 고른 임의의 지역으로, 다른 곳에 있는 서버의 로그를 읽을 때 원하는 줄입니다.
- UTC — 모든 시스템이 합의하는 기준이자 저장하고 로그하기에 옳은 것입니다.
- 로컬 — 사용자의 기기가 보는 것과 같은 순간이며, 판별한 지역 레이블이 붙습니다.
- 고른 지역 — 다른 곳의 머신에서 온 로그와 트레이스를 읽기 위한 것입니다.
- ISO 8601 — 교환용 텍스트 형식으로, 예를 들어 2024-05-20T09:33:20.000Z 입니다.
- 상대 — "3시간 전"처럼 얼마나 최근인지 빠르게 가늠하기 위한 것입니다.
오프셋(+03:00, -04:00)은 각 시각 옆에 표시됩니다. 고정이 아니기 때문입니다: 대부분의 지역은 서머타임으로 한 시간 옮겨지므로 같은 지역이라도 시기에 따라 다른 오프셋을 냅니다. 전환 근처의 날짜야말로 손 계산이 틀리는 자리입니다.
실무에서 에포크 시각 다루기
어느 언어든 셸이든 에포크 값을 만들고 읽는 저마다의 방법이 있습니다. 기억해 둘 만한 것은 다음과 같습니다:
date +%s # 셸: 현재 시각을 초로 date -d @1716197600 # 셸(GNU): 초에서 날짜로 Date.now() # JavaScript: 현재 시각을 밀리초로 new Date(1716197600 * 1000) # JavaScript: 초에서 Date로 time.time() # Python: 초, 부동소수점으로 datetime.fromtimestamp(1716197600, tz=timezone.utc) SELECT EXTRACT(EPOCH FROM now()) -- PostgreSQL: 초
대부분의 날짜 고통을 피하는 경험칙: 순간은 UTC로 저장·전송하고 — 에포크 정수든 ISO 8601 문자열이든 — 로컬 지역으로의 변환은 실제로 누군가에게 표시하는 마지막 순간까지 미루세요. 일찍 서식화하는 것이 시간대 버그를 표시 계층에 머물게 하지 않고 데이터에 구워 넣는 원인입니다.
한 가지 더 알아 둘 것: 부호 있는 32비트 초 카운터는 2038년 1월 19일에 소진됩니다. "2038년 문제"입니다. 현대 시스템은 64비트 값을 써서 괜찮지만, 오래된 임베디드 기기와 레거시 데이터베이스 열이야말로 그것을 아직 만날 수 있는 자리입니다.
자주 묻는 질문
- 제 숫자가 초인지 밀리초인지 어떻게 아나요?
- 그 크기로 압니다: 대략 1e11 미만의 값은 초로, 그보다 크면 밀리초로 읽습니다. 오늘은 이것이 10자리 초와 13자리 밀리초를 깔끔하게 나눕니다. 해석은 결과 옆에 표시되고 클릭 한 번으로 바꿀 수 있어 추측이 감춰지지 않습니다.
- "로컬"은 어느 시간대인가요?
- 사용자의 기기가 보고하는 지역으로, 브라우저 안에서 판별되고 헷갈리지 않도록 이름으로 표시됩니다. 사이트의 지역이 아니라 당신의 지역입니다 — 베를린의 방문자는 베를린 시각을, 서울의 방문자는 서울 시각을 봅니다.
- 날짜를 타임스탬프로 되돌릴 수 있나요?
- 네. 같은 입력란이 양방향을 받습니다: 숫자를 입력하면 날짜가, 2024-05-20이나 2024-05-20T09:33:20Z 같은 날짜를 입력하면 에포크 값이 나옵니다. 전환할 모드가 없습니다.
- 1970년 이전 날짜도 다루나요?
- 네. 에포크 이전의 타임스탬프는 그저 음수이며 — -86400은 1969년 12월 31일입니다 — 음수 값도 받아들여 평소대로 변환됩니다.
- 제 타임스탬프가 예상과 다른 날짜를 보이는 이유는 무엇인가요?
- 거의 늘 두 이유 중 하나입니다: 초/밀리초 해석이 짐작과 다르거나(레이블을 확인하고 바꾸세요), UTC 값을 로컬 시각 기대와 비교하고 있는 것입니다. 이 도구는 두 줄을 나란히 보여 주어 어느 쪽인지 알 수 있게 합니다.
- 2038년 문제란 무엇인가요?
- 에포크 초를 부호 있는 32비트 정수로 저장하는 시스템은 2038년 1월 19일에 넘쳐 음수로 되감겨 1901년 날짜를 냅니다. 64비트 값을 쓰는 것 — 현대의 거의 모든 것 — 은 영향받지 않지만, 레거시 임베디드 시스템과 오래된 데이터베이스 열은 지금도 위험할 수 있습니다.
- 입력한 타임스탬프가 어딘가로 전송되나요?
- 아니요. 파싱, 변환, 서식화가 모두 플랫폼 자체의 날짜·시간대 지원을 써서 브라우저 안에서 돕니다. 입력한 내용이 기기 밖으로 나가지 않습니다.