Intl.DateTimeFormat API
외부 라이브러리 없이 모든 로케일에 대한 날짜와 시간 형식 지정
소개
날짜는 전 세계적으로 다르게 표시됩니다. 2024년 1월 15일은 미국에서는 1/15/2024, 영국에서는 15/1/2024, 일본에서는 2024/1/15로 표시됩니다. 시간 형식도 다양합니다. 미국인들은 AM과 PM이 있는 12시간 시계를 사용하는 반면, 세계 대부분은 24시간 시간을 사용합니다.
다양한 로케일에 대한 수동 날짜 형식 지정 로직을 구축하는 것은 복잡하고 오류가 발생하기 쉽습니다. 일과 월의 순서, 구분 기호, 시간 형식, 시간대 변환, 비 그레고리안 달력과 같은 특수 사례를 처리해야 합니다.
Intl.DateTimeFormat API는 이 문제를 해결합니다. 모든 최신 브라우저에서 내장된 로케일 인식 날짜 및 시간 형식을 제공합니다. 외부 라이브러리가 필요하지 않습니다.
기본 사용법
날짜를 형식화하는 가장 간단한 방법은 Intl.DateTimeFormat 인스턴스를 생성하고 그 format() 메서드를 호출하는 것입니다.
const date = new Date(2024, 0, 15, 14, 30);
const formatter = new Intl.DateTimeFormat("en-US");
formatter.format(date);
// "1/15/2024"
로케일을 변경하여 다른 형식 지정 규칙을 확인할 수 있습니다.
const ukFormatter = new Intl.DateTimeFormat("en-GB");
ukFormatter.format(date);
// "15/01/2024"
const japanFormatter = new Intl.DateTimeFormat("ja-JP");
japanFormatter.format(date);
// "2024/1/15"
동일한 날짜가 지역 규칙에 따라 세 가지 다른 방식으로 형식화됩니다.
로케일 이해하기
로케일은 언어와 지역 환경설정을 식별하는 문자열입니다. 형식은 BCP 47 표준을 따릅니다: 언어 코드, 선택적으로 지역 코드가 뒤따릅니다.
일반적인 로케일 패턴:
"en" // 영어 (일반)
"en-US" // 영어 (미국)
"en-GB" // 영어 (영국)
"es" // 스페인어 (일반)
"es-MX" // 스페인어 (멕시코)
"es-ES" // 스페인어 (스페인)
"zh-CN" // 중국어 (중국, 간체)
"zh-TW" // 중국어 (대만, 번체)
로케일 매개변수를 생략하면 브라우저는 사용자의 기본 로케일을 사용합니다.
const formatter = new Intl.DateTimeFormat();
formatter.format(date);
// 출력은 사용자의 브라우저 로케일에 따라 달라집니다
로케일 배열을 제공할 수도 있습니다. 브라우저는 지원되는 첫 번째 로케일을 사용합니다.
const formatter = new Intl.DateTimeFormat(["es-MX", "es", "en"]);
// 가능한 경우 스페인어(멕시코)를 사용하고, 일반 스페인어, 그 다음 영어로 대체합니다
서식 옵션 개요
'Intl.DateTimeFormat' 생성자는 서식이 지정된 출력에 표시되는 내용을 제어하는 옵션 객체를 허용합니다. 서식 지정에는 두 가지 접근 방식이 있습니다.
첫 번째 접근 방식은 스타일 단축키를 사용합니다. 이는 빠르고 관례적인 서식을 제공합니다.
const formatter = new Intl.DateTimeFormat("en-US", {
dateStyle: "full",
timeStyle: "short"
});
formatter.format(date);
// "Monday, January 15, 2024 at 2:30 PM"
두 번째 접근 방식은 컴포넌트 옵션을 사용합니다. 이는 날짜의 각 부분에 대한 세밀한 제어를 제공합니다.
const formatter = new Intl.DateTimeFormat("en-US", {
year: "numeric",
month: "long",
day: "numeric",
hour: "numeric",
minute: "numeric"
});
formatter.format(date);
// "January 15, 2024 at 2:30 PM"
스타일 단축키와 컴포넌트 옵션을 혼합하여 사용할 수 없습니다. 포맷터당 하나의 접근 방식을 선택하세요.
스타일 단축키
'dateStyle'과 'timeStyle' 옵션은 네 가지 사전 설정된 서식 수준을 제공합니다.
'dateStyle' 옵션은 날짜 부분의 서식을 지정합니다.
const date = new Date(2024, 0, 15);
const full = new Intl.DateTimeFormat("en-US", { dateStyle: "full" });
full.format(date);
// "Monday, January 15, 2024"
const long = new Intl.DateTimeFormat("en-US", { dateStyle: "long" });
long.format(date);
// "January 15, 2024"
const medium = new Intl.DateTimeFormat("en-US", { dateStyle: "medium" });
medium.format(date);
// "Jan 15, 2024"
const short = new Intl.DateTimeFormat("en-US", { dateStyle: "short" });
short.format(date);
// "1/15/24"
'timeStyle' 옵션은 시간 부분의 서식을 지정합니다.
const date = new Date(2024, 0, 15, 14, 30, 45);
const full = new Intl.DateTimeFormat("en-US", { timeStyle: "full" });
full.format(date);
// "2:30:45 PM Eastern Standard Time"
const long = new Intl.DateTimeFormat("en-US", { timeStyle: "long" });
long.format(date);
// "2:30:45 PM EST"
const medium = new Intl.DateTimeFormat("en-US", { timeStyle: "medium" });
medium.format(date);
// "2:30:45 PM"
const short = new Intl.DateTimeFormat("en-US", { timeStyle: "short" });
short.format(date);
// "2:30 PM"
두 옵션을 모두 결합하여 날짜와 시간을 함께 서식 지정할 수 있습니다.
const formatter = new Intl.DateTimeFormat("en-US", {
dateStyle: "medium",
timeStyle: "short"
});
formatter.format(date);
// "Jan 15, 2024, 2:30 PM"
스타일 단축키는 로케일 규칙에 자동으로 적응합니다.
const usFormatter = new Intl.DateTimeFormat("en-US", {
dateStyle: "short",
timeStyle: "short"
});
usFormatter.format(date);
// "1/15/24, 2:30 PM"
const deFormatter = new Intl.DateTimeFormat("de-DE", {
dateStyle: "short",
timeStyle: "short"
});
deFormatter.format(date);
// "15.1.24, 14:30"
독일어 형식은 구분 기호로 점을 사용하고, 일과 월의 순서를 바꾸며, 24시간제로 시간을 표시합니다. 미국 형식은 슬래시를 사용하고, 월-일 순서로 표시하며, AM/PM이 있는 12시간제로 시간을 표시합니다. 동일한 옵션이지만 로케일에 따라 다른 출력이 생성됩니다.
컴포넌트 옵션
컴포넌트 옵션은 표시되는 내용과 방식에 대한 정밀한 제어를 제공합니다. 각 옵션은 날짜나 시간의 특정 부분을 지정합니다.
year 옵션은 연도를 표시합니다.
const formatter = new Intl.DateTimeFormat("en-US", { year: "numeric" });
formatter.format(date);
// "2024"
const twoDigit = new Intl.DateTimeFormat("en-US", { year: "2-digit" });
twoDigit.format(date);
// "24"
month 옵션은 다양한 형식으로 월을 표시합니다.
const numeric = new Intl.DateTimeFormat("en-US", { month: "numeric" });
numeric.format(date);
// "1"
const twoDigit = new Intl.DateTimeFormat("en-US", { month: "2-digit" });
twoDigit.format(date);
// "01"
const long = new Intl.DateTimeFormat("en-US", { month: "long" });
long.format(date);
// "January"
const short = new Intl.DateTimeFormat("en-US", { month: "short" });
short.format(date);
// "Jan"
const narrow = new Intl.DateTimeFormat("en-US", { month: "narrow" });
narrow.format(date);
// "J"
day 옵션은 월의 일자를 표시합니다.
const formatter = new Intl.DateTimeFormat("en-US", { day: "numeric" });
formatter.format(date);
// "15"
const twoDigit = new Intl.DateTimeFormat("en-US", { day: "2-digit" });
twoDigit.format(date);
// "15"
weekday 옵션은 요일을 표시합니다.
const long = new Intl.DateTimeFormat("en-US", { weekday: "long" });
long.format(date);
// "Monday"
const short = new Intl.DateTimeFormat("en-US", { weekday: "short" });
short.format(date);
// "Mon"
const narrow = new Intl.DateTimeFormat("en-US", { weekday: "narrow" });
narrow.format(date);
// "M"
여러 컴포넌트 옵션을 조합하여 사용자 정의 날짜 형식을 구성할 수 있습니다.
const formatter = new Intl.DateTimeFormat("en-US", {
weekday: "long",
year: "numeric",
month: "long",
day: "numeric"
});
formatter.format(date);
// "Monday, January 15, 2024"
브라우저는 로케일 규칙에 따라 간격과 구두점을 처리합니다.
시간 형식 지정
시간 컴포넌트 옵션은 시, 분, 초 표시를 제어합니다.
const date = new Date(2024, 0, 15, 14, 30, 45);
const formatter = new Intl.DateTimeFormat("en-US", {
hour: "numeric",
minute: "numeric",
second: "numeric"
});
formatter.format(date);
// "2:30:45 PM"
hour12 옵션은 12시간제와 24시간제 시간 표시를 제어합니다.
const hour12 = new Intl.DateTimeFormat("en-US", {
hour: "numeric",
minute: "numeric",
hour12: true
});
hour12.format(date);
// "2:30 PM"
const hour24 = new Intl.DateTimeFormat("en-US", {
hour: "numeric",
minute: "numeric",
hour12: false
});
hour24.format(date);
// "14:30"
hourCycle 옵션은 시간 표시에 대한 더 세밀한 제어를 제공합니다. 네 가지 옵션이 있습니다.
// h11: 0-11
const h11 = new Intl.DateTimeFormat("en-US", {
hour: "numeric",
hourCycle: "h11"
});
h11.format(new Date(2024, 0, 15, 0, 30));
// "0:30 AM"
// h12: 1-12
const h12 = new Intl.DateTimeFormat("en-US", {
hour: "numeric",
hourCycle: "h12"
});
h12.format(new Date(2024, 0, 15, 0, 30));
// "12:30 AM"
// h23: 0-23
const h23 = new Intl.DateTimeFormat("en-US", {
hour: "numeric",
hourCycle: "h23"
});
h23.format(new Date(2024, 0, 15, 0, 30));
// "0:30"
// h24: 1-24
const h24 = new Intl.DateTimeFormat("en-US", {
hour: "numeric",
hourCycle: "h24"
});
h24.format(new Date(2024, 0, 15, 0, 30));
// "24:30"
이 차이는 자정에 중요합니다. h11 사이클은 0을 사용하고, h12는 12를 사용합니다. 마찬가지로 h23은 0을 사용하고, h24는 24를 사용합니다.
dayPeriod 옵션은 12시간제 시간에 설명적인 기간 표시를 추가합니다.
const morning = new Date(2024, 0, 15, 10, 30);
const afternoon = new Date(2024, 0, 15, 14, 30);
const night = new Date(2024, 0, 15, 22, 30);
const formatter = new Intl.DateTimeFormat("en-US", {
hour: "numeric",
minute: "numeric",
dayPeriod: "long"
});
formatter.format(morning);
// "10:30 in the morning"
formatter.format(afternoon);
// "2:30 in the afternoon"
formatter.format(night);
// "10:30 at night"
dayPeriod 옵션은 12시간제 시간 형식에서만 작동합니다.
fractionalSecondDigits 옵션은 초 이하의 정밀도를 표시합니다.
const date = new Date(2024, 0, 15, 14, 30, 45, 123);
const oneDigit = new Intl.DateTimeFormat("en-US", {
hour: "numeric",
minute: "numeric",
second: "numeric",
fractionalSecondDigits: 1
});
oneDigit.format(date);
// "2:30:45.1 PM"
const threeDigits = new Intl.DateTimeFormat("en-US", {
hour: "numeric",
minute: "numeric",
second: "numeric",
fractionalSecondDigits: 3
});
threeDigits.format(date);
// "2:30:45.123 PM"
1, 2 또는 3개의 소수 자릿수를 지정할 수 있습니다.
시간대 처리
'timeZone' 옵션은 날짜를 특정 시간대로 변환합니다.
const date = new Date("2024-01-15T14:30:00Z"); // UTC 시간
const newYork = new Intl.DateTimeFormat("en-US", {
timeZone: "America/New_York",
dateStyle: "full",
timeStyle: "long"
});
newYork.format(date);
// "Monday, January 15, 2024 at 9:30:00 AM EST"
const tokyo = new Intl.DateTimeFormat("ja-JP", {
timeZone: "Asia/Tokyo",
dateStyle: "full",
timeStyle: "long"
});
tokyo.format(date);
// "2024年1月15日月曜日 23:30:00 日本標準時"
const london = new Intl.DateTimeFormat("en-GB", {
timeZone: "Europe/London",
dateStyle: "full",
timeStyle: "long"
});
london.format(date);
// "Monday, 15 January 2024 at 14:30:00 GMT"
동일한 시간이 시간대에 따라 다르게 표시됩니다. America/New_York, Europe/London, Asia/Tokyo와 같은 IANA 시간대 식별자를 사용하세요.
timeZoneName 옵션은 시간대 이름을 표시합니다.
const formatter = new Intl.DateTimeFormat("en-US", {
hour: "numeric",
minute: "numeric",
timeZone: "America/New_York",
timeZoneName: "short"
});
formatter.format(date);
// "9:30 AM EST"
const long = new Intl.DateTimeFormat("en-US", {
hour: "numeric",
minute: "numeric",
timeZone: "America/New_York",
timeZoneName: "long"
});
long.format(date);
// "9:30 AM Eastern Standard Time"
const shortOffset = new Intl.DateTimeFormat("en-US", {
hour: "numeric",
minute: "numeric",
timeZone: "America/New_York",
timeZoneName: "shortOffset"
});
shortOffset.format(date);
// "9:30 AM GMT-5"
const longOffset = new Intl.DateTimeFormat("en-US", {
hour: "numeric",
minute: "numeric",
timeZone: "America/New_York",
timeZoneName: "longOffset"
});
longOffset.format(date);
// "9:30 AM GMT-05:00"
다양한 timeZoneName 값은 서로 다른 수준의 세부 정보를 제공합니다.
달력 시스템 및 숫자 시스템
'calendar' 옵션은 그레고리안 달력이 아닌 다른 달력 시스템을 지원합니다.
const date = new Date(2024, 0, 15);
const gregorian = new Intl.DateTimeFormat("en-US", {
calendar: "gregory",
year: "numeric",
month: "long",
day: "numeric"
});
gregorian.format(date);
// "January 15, 2024"
const japanese = new Intl.DateTimeFormat("ja-JP", {
calendar: "japanese",
year: "numeric",
month: "long",
day: "numeric"
});
japanese.format(date);
// "令和6年1月15日"
const islamic = new Intl.DateTimeFormat("ar-SA", {
calendar: "islamic",
year: "numeric",
month: "long",
day: "numeric"
});
islamic.format(date);
// "٦ رجب ١٤٤٥"
const chinese = new Intl.DateTimeFormat("zh-CN", {
calendar: "chinese",
year: "numeric",
month: "long",
day: "numeric"
});
chinese.format(date);
// "2023甲辰年腊月初五"
동일한 날짜가 다른 달력 시스템으로 변환됩니다. 사용 가능한 달력에는 gregory, japanese, islamic, islamic-umalqura, islamic-tbla, islamic-civil, islamic-rgsa, chinese, hebrew, indian, persian 등이 있습니다.
numberingSystem 옵션은 다양한 문자 체계로 숫자를 표시합니다.
const date = new Date(2024, 0, 15);
const western = new Intl.DateTimeFormat("en-US", {
numberingSystem: "latn",
year: "numeric",
month: "numeric",
day: "numeric"
});
western.format(date);
// "1/15/2024"
const arabic = new Intl.DateTimeFormat("en-US", {
numberingSystem: "arab",
year: "numeric",
month: "numeric",
day: "numeric"
});
arabic.format(date);
// "١/١٥/٢٠٢٤"
const devanagari = new Intl.DateTimeFormat("en-US", {
numberingSystem: "deva",
year: "numeric",
month: "numeric",
day: "numeric"
});
devanagari.format(date);
// "१/१५/२०२४"
const bengali = new Intl.DateTimeFormat("en-US", {
numberingSystem: "beng",
year: "numeric",
month: "numeric",
day: "numeric"
});
bengali.format(date);
// "১/১৫/২০২৪"
사용 가능한 숫자 시스템에는 latn(서양 숫자), arab(아랍-인도 숫자), arabext(확장 아랍-인도 숫자), beng(벵골 숫자), deva(데바나가리 숫자) 등 다양한 시스템이 포함됩니다.
날짜 범위 포맷팅
'formatRange()' 메서드는 중복되는 정보를 스마트하게 생략하여 날짜 범위를 포맷팅합니다.
const start = new Date(2024, 0, 15);
const end = new Date(2024, 0, 20);
const formatter = new Intl.DateTimeFormat("en-US", {
year: "numeric",
month: "long",
day: "numeric"
});
formatter.formatRange(start, end);
// "January 15 – 20, 2024"
포맷터는 반복되는 정보를 생략합니다. 두 날짜 모두 2024년 1월이므로, 출력에는 월과 연도가 한 번만 포함됩니다.
범위가 다른 월에 걸쳐 있을 때는 두 월 모두 표시됩니다.
const start = new Date(2024, 0, 15);
const end = new Date(2024, 1, 20);
formatter.formatRange(start, end);
// "January 15 – February 20, 2024"
범위가 다른 연도에 걸쳐 있을 때는 모든 정보가 표시됩니다.
const start = new Date(2024, 0, 15);
const end = new Date(2025, 1, 20);
formatter.formatRange(start, end);
// "January 15, 2024 – February 20, 2025"
'formatRange()' 메서드는 시간 범위에도 작동합니다.
const start = new Date(2024, 0, 15, 14, 30);
const end = new Date(2024, 0, 15, 16, 45);
const formatter = new Intl.DateTimeFormat("en-US", {
month: "long",
day: "numeric",
hour: "numeric",
minute: "numeric"
});
formatter.formatRange(start, end);
// "January 15, 2:30 – 4:45 PM"
두 시간 모두 같은 날에 발생하므로 날짜는 한 번만 표시됩니다.
포맷팅된 부분 접근하기
'formatToParts()' 메서드는 포맷팅된 날짜의 각 부분을 나타내는 객체 배열을 반환합니다. 이를 통해 사용자 정의 포맷팅 로직을 구현할 수 있습니다.
const date = new Date(2024, 0, 15, 14, 30);
const formatter = new Intl.DateTimeFormat("en-US", {
year: "numeric",
month: "long",
day: "numeric",
hour: "numeric",
minute: "numeric"
});
const parts = formatter.formatToParts(date);
배열의 각 객체는 'type'과 'value' 속성을 가집니다.
[
{ type: "month", value: "January" },
{ type: "literal", value: " " },
{ type: "day", value: "15" },
{ type: "literal", value: ", " },
{ type: "year", value: "2024" },
{ type: "literal", value: " at " },
{ type: "hour", value: "2" },
{ type: "literal", value: ":" },
{ type: "minute", value: "30" },
{ type: "literal", value: " " },
{ type: "dayPeriod", value: "PM" }
]
이러한 부분들을 필터링하고 조작하여 사용자 정의 형식을 만들 수 있습니다.
const dateParts = parts.filter(part =>
["month", "day", "year"].includes(part.type)
);
const dateString = dateParts.map(part => part.value).join("/");
// "January/15/2024"
'formatRangeToParts()' 메서드는 날짜 범위에 대해 동일한 기능을 제공합니다.
const start = new Date(2024, 0, 15);
const end = new Date(2024, 0, 20);
const formatter = new Intl.DateTimeFormat("en-US", {
year: "numeric",
month: "long",
day: "numeric"
});
const parts = formatter.formatRangeToParts(start, end);
각 부분 객체에는 시작 날짜 또는 종료 날짜에서 가져온 것인지를 나타내는 'source' 속성이 포함됩니다.
[
{ type: "month", value: "January", source: "startRange" },
{ type: "literal", value: " ", source: "startRange" },
{ type: "day", value: "15", source: "startRange" },
{ type: "literal", value: " – ", source: "shared" },
{ type: "day", value: "20", source: "endRange" },
{ type: "literal", value: ", ", source: "shared" },
{ type: "year", value: "2024", source: "shared" }
]
모범 사례
동일한 옵션으로 여러 날짜를 포맷팅할 때는 포맷터 인스턴스를 재사용하세요. 포맷터를 생성하는 것은 로케일 협상과 옵션 해결을 포함하며, 이는 작은 성능 비용이 발생합니다.
// 덜 효율적인 방법
dates.forEach(date => {
const formatted = new Intl.DateTimeFormat("en-US").format(date);
console.log(formatted);
});
// 더 효율적인 방법
const formatter = new Intl.DateTimeFormat("en-US");
dates.forEach(date => {
const formatted = formatter.format(date);
console.log(formatted);
});
가능한 경우 로케일 매개변수를 생략하여 사용자의 브라우저 로케일을 사용하세요. 이는 사용자 환경설정을 존중합니다.
const formatter = new Intl.DateTimeFormat();
// 브라우저 로케일을 자동으로 사용
특정 지역을 대상으로 할 때는 대체 로케일을 제공하세요. 선호하는 로케일을 사용할 수 없는 경우 브라우저는 다음 옵션을 사용합니다.
const formatter = new Intl.DateTimeFormat(["fr-CA", "fr", "en"]);
// 프랑스어(캐나다)를 선호하고, 프랑스어, 그다음 영어로 대체
일반적인 날짜 및 시간 표시에는 스타일 단축키를 사용하세요. 이는 로케일 규칙에 자동으로 적응하고 구성이 적게 필요합니다.
const formatter = new Intl.DateTimeFormat("en-US", {
dateStyle: "medium",
timeStyle: "short"
});
출력 형식에 대한 정밀한 제어가 필요할 때는 컴포넌트 옵션을 사용하세요.
const formatter = new Intl.DateTimeFormat("en-US", {
weekday: "long",
year: "numeric",
month: "long",
day: "numeric"
});
원격 사용자에게 시간을 표시하거나 예약된 이벤트의 경우 항상 시간대를 지정하세요. 시간대가 없으면 날짜는 사용자의 로컬 시간대로 포맷되며, 이는 의도와 일치하지 않을 수 있습니다.
const formatter = new Intl.DateTimeFormat("en-US", {
timeZone: "America/New_York",
dateStyle: "full",
timeStyle: "long"
});
각 날짜를 별도로 포맷하고 연결하는 대신 날짜 범위에는 formatRange()를 사용하세요. 이 메서드는 중복 정보의 스마트한 생략을 처리합니다.
// 덜 명확한 방법
const startFormatted = formatter.format(start);
const endFormatted = formatter.format(end);
const range = `${startFormatted} to ${endFormatted}`;
// 더 나은 방법
const range = formatter.formatRange(start, end);
dayPeriod, fractionalSecondDigits 및 특정 timeZoneName 값과 같은 고급 기능에 대한 브라우저 호환성을 확인하세요. 모든 최신 브라우저는 핵심 기능을 지원하지만, 새로운 옵션은 구형 브라우저에 대한 대체 방안이 필요할 수 있습니다.