밀리초를 초로 — 개발자를 위한 시간 변환 참고서
밀리초는 소프트웨어 개발에서 끊임없이 나타난다. 타임아웃을 5000ms로 설정한다. API 요청 제한은 "10초당 100개 요청"이라고 한다. 애니메이션이 300ms 동안 실행된다. Unix 타임스탬프는 JavaScript에서는 밀리초지만 Python에서는 초다. 변환은 간단하다 — 1초 = 1,000밀리초 — 하지만 자주 쓰는 값들을 손에 있으면 계산 부담이 줄어든다.
시간 변환 도구는 밀리초, 초, 분, 시간 등을 다룬다. 이 글은 개발자가 가장 자주 마주치는 값들을 담은 실용적인 참고서다.
기본 변환
1초 = 1,000밀리초
1밀리초 = 0.001초
초 = 밀리초 ÷ 1,000
밀리초 = 초 × 1,000
나머지는 여기서 나온다:
- 1분 = 60,000ms
- 1시간 = 3,600,000ms
- 1일 = 86,400,000ms
코드에서 자주 쓰는 값들
이 값들은 코드를 작성하거나 읽을 때 정기적으로 마주친다:
| 지속 시간 | 밀리초 | 초 |
|---|---|---|
| 60fps에서 한 프레임 | ~16ms | 0.016초 |
| 애니메이션 전환 (빠름) | 150–200ms | 0.15–0.2초 |
| 애니메이션 전환 (보통) | 250–300ms | 0.25–0.3초 |
| 애니메이션 전환 (느림) | 400–600ms | 0.4–0.6초 |
| 평균 인간 반응 시간 | ~250ms | 0.25초 |
| HTTP 요청 타임아웃 (빠름) | 1,000ms | 1초 |
| HTTP 요청 타임아웃 (표준) | 5,000ms | 5초 |
| HTTP 요청 타임아웃 (넉넉함) | 30,000ms | 30초 |
| 요청 제한 창 | 60,000ms | 60초 (1분) |
| JWT 토큰 만료 (짧음) | 900,000ms | 900초 (15분) |
| JWT 토큰 만료 (표준) | 3,600,000ms | 3,600초 (1시간) |
| 일일 요청 제한 창 | 86,400,000ms | 86,400초 (24시간) |
| 세션 타임아웃 (표준) | 1,800,000ms | 1,800초 (30분) |
참고표: 초에서 밀리초로
| 초 | 밀리초 |
|---|---|
| 0.1초 | 100ms |
| 0.25초 | 250ms |
| 0.5초 | 500ms |
| 1초 | 1,000ms |
| 2초 | 2,000ms |
| 5초 | 5,000ms |
| 10초 | 10,000ms |
| 15초 | 15,000ms |
| 30초 | 30,000ms |
| 60초 (1분) | 60,000ms |
| 120초 (2분) | 120,000ms |
| 300초 (5분) | 300,000ms |
| 600초 (10분) | 600,000ms |
| 900초 (15분) | 900,000ms |
| 1,800초 (30분) | 1,800,000ms |
| 3,600초 (1시간) | 3,600,000ms |
| 86,400초 (1일) | 86,400,000ms |
여러 언어와 환경에서의 밀리초
언어와 환경마다 기본 시간 단위가 다르다. 이는 미묘한 버그의 흔한 원인이다.
JavaScript: Date.now()는 밀리초를 반환한다. setTimeout(fn, 5000)은 밀리초를 받는다. new Date().getTime()은 밀리초를 반환한다.
const ts_ms = Date.now(); // 밀리초
const ts_s = Math.floor(Date.now() / 1000); // 초
setTimeout(fn, 5 * 1000); // 5초를 밀리초로
Python: time.time()은 초(실수)를 반환한다. time.sleep(5)는 초를 받는다.
import time
ts_s = time.time() # 초 (실수)
ts_ms = time.time() * 1000 # 밀리초
time.sleep(0.5) # 500ms를 초로
Node.js process.hrtime(): 나노초(매우 높은 정밀도)를 반환한다. performance.now()는 밀리초를 반환한다.
const start = performance.now();
// ... 어떤 작업 ...
const elapsed_ms = performance.now() - start;
const elapsed_s = elapsed_ms / 1000;
CSS 애니메이션과 전환: 초 단위를 사용한다.
transition: all 0.3s ease; /* 300ms */
animation-duration: 1.5s; /* 1500ms */
Redis TTL: EXPIRE key seconds — 초를 받는다. 밀리초 버전은 PEXPIRE key milliseconds다.
Cron 표현식: 가장 세밀한 단위가 초다(Spring의 @Scheduled 같은 구현은 초를 지원하고, 표준 Unix cron은 분 단위).
Unix 타임스탐프: 초 vs 밀리초
밀리초와 관련된 가장 흔한 크로스 언어 버그는 Unix 타임스탐프다.
- Unix 표준은 에포크(1970년 1월 1일) 이후 초
- JavaScript의
Date.now()는 에포크 이후 밀리초 - 초 타임스탐프는 10자리(현재 약 17억)
- 밀리초 타임스탐프는 13자리(현재 약 1.7조)
JavaScript 밀리초 타임스탐프를 초를 기대하는 Python 백엔드로 보내면 55,000년의 날짜가 된다. 초 타임스탐프를 JavaScript의 new Date()로 보내면 1970년의 날짜가 된다.
판별 방법:
- 10자리 = 초
- 13자리 = 밀리초
// 입력 형식과 관계없이 초로 정규화
function toSeconds(ts) {
return ts > 9999999999 ? Math.floor(ts / 1000) : ts;
}
성능 측정
코드를 프로파일링하거나 실행 시간을 측정할 때, 측정하는 대상에 따라 밀리초와 마이크로초가 나타난다.
| 규모 | 단위 | 사용 예 |
|---|---|---|
| 1ms 미만 | 마이크로초(µs) | CPU 연산, 메모리 접근 |
| 1–100ms | 밀리초 | 데이터베이스 쿼리, API 호출, 렌더링 |
| 100–1,000ms | 밀리초 | 느린 쿼리, 이미지 처리 |
| 1초 이상 | 초 | 페이지 로드 시간, 배치 처리 |
웹 성능 기준:
- 100ms 미만: 즉각적으로 느껴짐
- 100–300ms: 눈에 띄지만 괜찮음
- 300–1,000ms: 느리게 느껴짐. 로딩 표시 필요할 수 있음
- 1초 이상: 사용자가 "로딩 중"으로 인식
Google의 Core Web Vitals는 밀리초를 사용한다: Largest Contentful Paint(LCP)는 2,500ms 이하여야 하고, Interaction to Next Paint(INP)는 200ms 이하, Cumulative Layout Shift는 단위가 없다.
요청 제한과 속도 제한
요청 제한은 종종 시간 창당 요청 수로 표현된다. 창을 밀리초로 변환하면 속도 제한 로직을 구현할 때 유용하다:
| 요청 제한 | 창의 ms | 요청 간 최소 시간 |
|---|---|---|
| 초당 100개 요청 | 1,000ms | 최소 10ms |
| 분당 60개 요청 | 60,000ms | 최소 1,000ms |
| 시간당 1,000개 요청 | 3,600,000ms | 최소 3,600ms |
| 일당 10,000개 요청 | 86,400,000ms | 최소 8,640ms |
간단한 속도 제한 구현은 창을 밀리초로 사용한다:
const RATE_LIMIT_WINDOW_MS = 60 * 1000; // 60초
const MAX_REQUESTS = 60;
// 평균 1,000ms마다 한 요청
const MIN_INTERVAL_MS = RATE_LIMIT_WINDOW_MS / MAX_REQUESTS; // 1000
밀리초 이외의 다른 시간 단위 변환 — 일에서 시간, 주에서 분, 년에서 초 — 은 시간 변환 도구에서 전체 범위를 다룬다.
