Unix 타임스탬프 변환기
1. 1714545437 은 정확히 언제인가요?
클라이언트 혹은 서버간의 통신중에 다음과 같이 시간이 전달되는 경험을 해보신 적이 있습니다. 서비스에서 시간을 표현할 때 사용되는 표기법으로 Unix timestamp 혹은 Epoch time이라고 부릅니다.
API 데이터를 주고받을때 주로 사용되며, 서버, 클라이언트간의 시간 표시 통합 및 시간 연산등이 편하다는 장점을 가지고 있습니다. 하지만, 직관적이게 언제인지 파악하기가 어렵고, 특정시간(예를들면 오늘)을 해당 표기법으로 표현하는 것이 어렵기 때문에 디버깅이나 데이터베이스에 값을 조회하는데 어려움을 겪어보신적이 있을거라 생각합니다.
이럴때 빠르게 해당 시간대를 사람이 읽을 수 있는 포맷(이하 표준 시간 포멧으로 칭함)으로 빠르게 변환하는 방법을 알아보겟습니다.
a. 온라인에서 확인하기
온라인 무료 유틸리티 도구 서비스에는 빠르게 Unix Timestamp를 확인할 수 있는 기능을 제공합니다. UtilZip은 Unix Timestamp로 표현된 시간을 빠르게 사람이 읽기 편한 형태로 제공하며, 사용자가 Unix Timestamp로 변환하고 싶은 시간대를 입력하면 바로 변환할 수 있도록 구현해두었습니다.
b. CLI 명령어로 확인하기
OS별로 CLI에서 빠르게 확인이 가능합니다.
# 1. epoch time을 표준 시간 포맷으로 변환
date -r 1714545437
>>> 2024년 5월 1일 수요일 15시 37분 17초 KST
#
# 2. 표준 시간 포맷을 Epoch time으로 변환
date -j -f "%Y-%m-%d %H:%M:%S" "2024-05-01 15:37:17" "+%s"
>>> 1714545437
# 1. epoch time을 표준 시간 포맷으로 변환
date -d @1714545437
>>> Wed May 1 15:37:17 KST 2024
#
# 2. 표준 시간 포맷을 Epoch time으로 변환
date -d "2024-05-01 15:37:17" +"%s"
>>> 1714545437
# 1. epoch time을 표준 시간 포맷으로 변환
[DateTimeOffset]::FromUnixTimeSeconds(1714545437).LocalDateTime
>>> 2024-05-01 오후 3:37:17
#
# 2. 표준 시간 포맷을 Epoch time으로 변환
[DateTimeOffset]::new([DateTime]"2024-05-01 15:37:17").ToUnixTimeSeconds()
>>> 1714545437
2. Unix 타임스탬프 생성 원리
Unix 타임스탬프(또는 epoch time)는 1970년 1월 1일 00:00:00 UTC를 0으로 두고, 그로부터 흐른 초의 누적값을 정수로 표현한 시간 표현 방식입니다. 1970년 이전 시점은 음수로 표현됩니다.
a. 단위 표기
시스템마다 시간 단위를 저장하는 방법이 모두 다릅니다. 같은 시점도 단위가 다르게 표현되면 다른 시간이되고 서로 연산도 불가능해집니다. 특히나 시스템간의 단위 표현이 달라서 잘 맞춰서 시간 데이터를 저장하는 것이 중요하며, 혹여나 다르더라도 연산을 위해서 단위를 맞춰서 연산하는 것이 좋습니다.
아래는 단위 표기 및 해당 단위에 대한 사용처를 정리한 것 입니다.
| 단위 | 예시 (2026-05-04 기준) | 자릿수 | 주요 사용처 |
|---|---|---|---|
| 초(seconds) | 1746345600 | 10자리 | Unix 시스템, JWT의 exp, 대부분의 백엔드 |
| 밀리초(milliseconds) | 1746345600000 | 13자리 | JavaScript Date.now(), Java System.currentTimeMillis() |
| 마이크로초(microseconds) | 1746345600000000 | 16자리 | 일부 Python 라이브러리, 정밀 로깅 |
3. 실무에서 마주치는 순간들
a. 장애 시점 추적
여러 시스템의 로그를 한 줄로 꿰는 작업은 거의 항상 타임스탬프 변환에서 시작됩니다. PG사가 보내온 리포트의 1746345600을 KST로 환산해 우리 시스템 로그에서 동일 시점을 찾아내는 식입니다. 모든 로그를 UTC로 통일하고, 검색 시점에만 KST로 변환하는 운영 패턴이 가장 안전합니다.
b. JWT의 iat, exp 클레임 검증
JWT 토큰은 발급 시각(iat)과 만료 시각(exp)을 Unix 타임스탬프(초 단위)로 저장합니다. 토큰 디버깅 중 "이 토큰은 언제 만료되지?"라는 질문이 나왔을 때, exp 값을 즉시 사람 읽는 시각으로 바꿔 확인하는 일이 잦습니다.
c. 데이터베이스 스키마 설계
새 테이블의 시간 컬럼을 어떻게 저장할지는 영원히 반복되는 논쟁거리입니다.
BIGINT타입의 epoch milliseconds 저장: 시간대 모호함이 없고, 인덱싱과 비교 연산이 가벼움.TIMESTAMP WITH TIME ZONE: PostgreSQL이 권장하는 방식으로, 시간대 정보를 함께 보존.DATETIME또는TIMESTAMP: MySQL의TIMESTAMP는 내부적으로 UTC로 저장되지만,DATETIME은 시간대 없이 그대로 저장되어 사고를 부른다.
d. 캐시 만료, 토큰 갱신, 배치 작업
expires_at, next_run_at, scheduled_for 같은 필드는 거의 모두 epoch time으로 저장됩니다. 디버깅할 때 이 값을 즉시 사람 읽는 시각으로 바꿔 보면, "왜 캐시가 안 비워지지?", "왜 배치가 실행 안 됐지?" 같은 질문에 빠르게 답할 수 있습니다.
4. 시간이 어긋나서 생기는 버그
서비스 개발중에 흔하게 발생할 수 있는 버그들을 아래에 정리하였습니다. 흔히 발생할 수 있는 문제들은 다음과 같으니 발생할 수 있는 문제들을 잘 참고하시면 좋을 것 같습니다.
1. 단위 혼동 (초 vs 밀리초)
사실 타임스탬프 관련 버그의 대부분이 여기서 발생한다고 생각합니다. 백엔드는 초 단위로 보냈는데 프론트엔드의 new Date()가 그것을 밀리초로 해석하면, 1970년 1월 어느 시점이 화면에 표시되는 어이없는 결과가 나옵니다.
// 잘못된 예시 — 초 단위 값을 밀리초로 해석
new Date(1746345600);
// → "Wed Jan 21 1970 09:25:45" — 1970년!
// 올바른 예시 — 1000을 곱해 밀리초로 변환
new Date(1746345600 * 1000);
// → "2026-05-04T05:30:00.000Z"
이런 사고를 막으려면 API 명세에 단위를 명시적으로 적어 두는 것이 가장 확실합니다. 필드 이름을 created_at_ms, expires_at_sec처럼 단위를 포함시키는 컨벤션도 효과적입니다.
2. 시간대 변환 누락
서버는 UTC 기준으로 동작하는데 응답을 만들 때 KST로 변환하는 과정을 빠뜨리면, 사용자에게 9시간 어긋난 시각이 보이게 됩니다. 반대로 클라이언트에서 입력받은 KST 시각을 UTC로 정규화하지 않고 그대로 저장하면, 데이터베이스에 잘못된 시점이 박혀 버립니다.
회사 정책에 따라 다르겠지만, 실무에서 가장 무난한 패턴은 다음과 같습니다.
- 저장: 항상 UTC 기준 epoch 또는
TIMESTAMPTZ로 저장. - API 응답: ISO 8601 형식으로 UTC 또는 명시적인 시간대 오프셋과 함께 반환.
- 클라이언트 표시: 사용자의 로컬 시간대로 변환해 보여주기.
3. 공통 해결책: 단위와 시간대를 정확히 명시하기
단위 혼동이든 시간대 누락이든, 시간 관련 버그를 다루는 해결책의 핵심은 시간 값에 항상 메타 정보를 동반시키는 것입니다. 필드명에 단위를 박아 넣고, API 명세에 시간대를 표시하고, 로그에는 항상 ISO 8601 형식으로 남기는 것. 이 세 가지만 지켜도 시간 관련 사고의 대부분을 예방할 수 있습니다.
생각해볼 내용들
타임스탬프 자체는 단순합니다. 어려운 것은 모든 시스템 경계에서 단위와 시간대를 일관되게 지키는 것이고, 한번 잘못 들어간 시간 값을 거꾸로 추적하는 일입니다. 이 도구를 만든 이유도 결국 그 추적 과정의 마찰을 줄이기 위해서였습니다.
다만 몇 가지 근본적인 질문은 남습니다.
서로 다른 시스템의 시계가 어긋나면? 분산 시스템에서는 NTP 동기화에도 불구하고 노드 간 시각이 수 밀리초씩 차이날 수 있습니다. 이런 환경에서 "어떤 이벤트가 먼저 일어났는지" 판단하려면 단순 타임스탬프 비교만으로는 부족하고, Lamport clock이나 Vector clock 같은 논리적 시계 개념을 도입해야 합니다. 단일 서비스라면 거의 무관하지만, 글로벌 분산 환경에서는 한 번쯤 짚어봐야 할 주제입니다.
2038년 문제에 우리 시스템은 안전한가? 64비트 정수를 쓴다면 거의 모든 경우에 안전합니다. 그러나 오래된 데이터베이스 컬럼이 INT(11)처럼 32비트로 정의되어 있거나, 임베디드 펌웨어가 32비트 시간 표현을 그대로 쓰고 있다면 점검이 필요합니다. 새 프로젝트라면 모든 시간 컬럼을 BIGINT 또는 TIMESTAMPTZ로 통일하는 것이 가장 안전한 선택입니다.
언젠가 epoch 자체가 바뀔 수 있을까? 1970년 기준점은 사실상 영구적인 약속처럼 보이지만, 64비트 정수로도 표현 불가능한 시점이 등장하거나, 컴퓨팅 패러다임이 바뀌면 기준 자체가 달라질 수도 있습니다. 그때를 대비해 시간 처리 로직을 한 곳에 집중시키고, 추후 마이그레이션이 가능한 구조로 분리해 두는 것은 항상 좋은 습관입니다.
브라우저 탭 하나로 10자리 숫자를 한국 시각으로, 또는 그 반대로 즉시 변환할 수 있다면 — 장애 분석에 들어가는 시간이 절반으로 줄어듭니다. 그것만으로도 이 도구의 역할은 충분하다고 생각합니다.