javascript 날짜 포맷 변환: 실무 적용 가이드와 코드 예제
javascript 날짜 포맷 변환을 실무 관점에서 정리한 글입니다. 기본 개념, Intl과 라이브러리 비교, 코드 예제, 주의점과 체크리스트를 통해 바로 적용 가능한 방법을 제공합니다.
javascript 날짜 포맷 변환이 필요한 상황
javascript 날짜 포맷 변환은 웹 애플리케이션에서 사용자에게 날짜와 시간을 읽기 쉬운 형태로 제공하거나, API와의 호환을 맞출 때 자주 필요합니다. 이 글에서는 개념 이해, 표준 API(Intl)와 라이브러리(date-fns, Luxon 등) 비교, 실무 코드 예제, 주의점과 체크리스트까지 다루어 바로 적용할 수 있게 안내합니다.
javascript 날짜 포맷 변환 핵심 개념
날짜 포맷 변환의 핵심은 다음과 같습니다.
- 내부 표현: 자바스크립트는 Date 객체(UTC와 로컬 표기)와 타임스탬프(밀리초)를 사용합니다.
- 포맷 방법: 수동 포맷(문자열 조작), Intl.DateTimeFormat(브라우저/환경 제공), 외부 라이브러리(date-fns, Luxon 등).
- 타임존 처리: 로컬 타임존과 UTC, 사용자가 지정한 타임존 중 어떤 것을 보여줄지 결정해야 합니다.
중요: 사용자 로케일과 타임존을 고려하지 않으면 날짜 표시가 오해를 낳을 수 있습니다. 실무에서는 가능한 Intl API를 우선 고려하고, 복잡한 요구(타임존 변환, 상대 시간, 커스텀 포맷)가 있으면 외부 라이브러리를 사용하세요.
javascript 날짜 포맷 변환 실무 예제
아래 예제들은 브라우저와 Node 환경에서 자주 쓰이는 방식들을 정리한 것입니다.
- 브라우저/Node 표준: Intl.DateTimeFormat 사용
// en-US 기준으로 날짜/time 포맷 const date = new Date('2023-08-15T13:45:30Z'); const fmt = new Intl.DateTimeFormat('ko-KR', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit', timeZone: 'Asia/Seoul' }); console.log(fmt.format(date)); // 2023.08.15. 22:45:30 (로컬/타임존 설정에 따라 다름)
- date-fns로 포맷 제어 (경량/모듈화)
import { format, utcToZonedTime } from 'date-fns-tz'; const date = new Date('2023-08-15T13:45:30Z'); const zoned = utcToZonedTime(date, 'Asia/Seoul'); console.log(format(zoned, 'yyyy-MM-dd HH:mm:ss')); // 2023-08-15 22:45:30
- 간단한 수동 포맷 함수 (작고 종속성 없는 경우)
function pad(n){return n<10? '0'+n : String(n)} function formatDate(d){ return `${d.getFullYear()}-${pad(d.getMonth()+1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`; } console.log(formatDate(new Date()));
비교: 표준 API vs 라이브러리 vs 수동 포맷
| 구분 | 항목1 | 항목2 | 항목3 |
|---|---|---|---|
| 내용 | 표준(Intl.DateTimeFormat) | 라이브러리(date-fns, Luxon) | 수동 포맷(직접 구현) |
| 내용 | 로케일/타임존 기본 지원, 번들 크기 없음 | 풍부한 기능(기간, 타임존 변환 등), 유지보수 편의 | 의존성 없음, 커스텀 가능하지만 오류 위험 |
| 내용 | 브라우저/Node 환경별 지원 차이 존재 | 추가 번들/폴리필 필요할 수 있음 | 복잡한 요구에 비효율적 |
언제 쓰면 좋고 언제 피해야 할까
언제 쓰면 좋은가
- 간단한 로케일 기반 포맷: Intl.DateTimeFormat 사용
- 복잡한 타임존 변환, 기간 연산: date-fns 또는 Luxon 사용
- 외부 라이브러리 도입이 부담스러울 때: 수동 포맷
언제 피해야 하는가
- 브라우저 호환성 문제를 확인하지 않고 Intl에만 의존할 때
- 대규모 애플리케이션에서 모든 날짜 로직을 수동 구현할 때
- 성능에 민감한 루프 안에서 무거운 라이브러리를 반복 호출할 때
실무 체크리스트
- 사용자 로케일(locale)과 타임존(timeZone) 요구사항을 명확히 했는가?
- 서버와 클라이언트 간 날짜 표기 규약(UTC 또는 로컬)을 정했는가?
- 라이브러리 도입 시 번들 사이즈와 트리 쉐이킹 여부를 검토했는가?
- Intl 미지원 환경(구형 브라우저) 대응 폴리필이 필요한가?
- 날짜 포맷 관련 단위 테스트와 회귀 테스트가 준비되었는가?
성능·보안·운영 주의점
- 성능: 대량 데이터 렌더링 시 포맷 함수를 루프 바깥으로 빼거나 캐시하세요. Intl 인스턴스를 매번 새로 만들면 비용이 발생하므로 재사용이 가능하면 재사용합니다.
- 보안: 날짜 문자열을 파싱할 때 사용자 입력을 그대로 Date에 넘기지 마세요. 형식 검증(정규식 또는 ISO 형식 강제)을 통해 예외/잘못된 입력을 방지합니다.
- 운영: 로그와 저장은 가능하면 UTC로 통일하고, UI에서만 로케일/타임존 변환을 적용하세요. 데이터베이스에 로컬 시간 저장은 혼란을 초래할 수 있습니다.
javascript 날짜 포맷 변환 구현 판단 기준표
| 구분 | 항목1 | 항목2 | 항목3 |
|---|---|---|---|
| 내용 | 요구 복잡도 | 권장 접근 | 이유 |
| 내용 | 단순 표시 (로케일 기반) | Intl.DateTimeFormat | 번들 크기 없음, 표준 지원 |
| 내용 | 타임존 변환/기간 계산 | date-fns/Luxon | 기능 풍부, 명확한 API |
| 내용 | 초경량 프로젝트 | 수동 포맷/유틸 | 의존성 제거, 직접 제어 가능 |
javascript 날짜 포맷 변환 실무 팁
- Intl.DateTimeFormat은 로케일 문자열('ko-KR')과 옵션을 통해 대부분의 표현을 처리합니다.
- date-fns는 함수별 임포트로 트리 쉐이킹이 잘 되므로 번들 크기 부담을 줄일 수 있습니다.
- ISO 8601 문자열('YYYY-MM-DDTHH:mm:ssZ')을 표준으로 사용하면 파싱/비교에 유리합니다.
자주 묻는 질문
Q1: Intl.DateTimeFormat은 모든 브라우저에서 동일하게 동작하나요? A1: 대부분 현대 브라우저는 지원하지만 구형 브라우저나 일부 JS 런타임에서는 옵션 차이나 일부 기능 미지원이 있을 수 있습니다. 필요시 폴리필을 검토하세요.
Q2: UTC로 저장해야 하나요, 로컬로 저장해야 하나요? A2: 운영상 권장되는 패턴은 저장은 UTC(정규화), 표시 시 로컬/사용자 설정에 맞춰 변환하는 것입니다. 이렇게 하면 시간 비교와 정렬에서 일관성이 생깁니다.
Q3: moment.js를 계속 사용해도 될까요? A3: moment.js는 안정적이지만 크기가 크고 모던 트리쉐이킹에 부적합합니다. 새로운 프로젝트라면 date-fns나 Luxon 같은 경량 대안을 권장합니다.
Q4: 서버에서 받은 타임스탬프를 클라이언트에서 사용하면 문제가 생기나요? A4: 서버가 UTC로 보내면 클라이언트가 로컬 타임존에 맞춰 표시하면 일반적으로 문제가 없습니다. 단, DST(서머타임)와 같은 예외 케이스를 고려해야 합니다.
정리
- javascript 날짜 포맷 변환은 Intl 우선, 복잡한 요구는 전문 라이브러리 사용을 권장합니다.
- 저장은 UTC, 표시만 로컬/사용자 설정으로 처리하세요.
- 성능을 위해 포맷터 재사용과 캐싱을 고려하고, 입력 검증으로 파싱 오류를 방지하세요.
- 체크리스트와 비교표를 통해 요구에 맞는 방식을 선택하세요.
- 코드 예제를 바로 복사해 환경에 맞게 옵션(로케일, 타임존)을 조정해 사용하세요.