JavaScript에서 형식화된 날짜의 개별 부분을 가져오는 방법
formatToParts()를 사용하여 로케일 형식화된 날짜의 각 구성 요소에 개별적으로 액세스하기
소개
format() 메서드는 "January 15, 2025" 또는 "15/01/2025"와 같은 완전히 포맷된 문자열을 반환합니다. 이는 간단한 표시에는 적합하지만, 개별 부분을 다르게 스타일링할 수 없습니다. 월 이름을 굵게 만들거나, 연도를 다른 색상으로 표시하거나, 특정 구성 요소에 사용자 정의 마크업을 적용할 수 없습니다.
JavaScript는 이 문제를 해결하기 위해 formatToParts() 메서드를 제공합니다. 단일 문자열을 반환하는 대신, 포맷된 날짜의 각 부분을 나타내는 객체 배열을 반환합니다. 각 부분은 month, day 또는 year와 같은 타입과 January, 15 또는 2025와 같은 값을 가집니다. 그런 다음 이러한 부분을 처리하여 사용자 정의 스타일을 적용하거나, 복잡한 레이아웃을 구축하거나, 포맷된 날짜를 풍부한 사용자 인터페이스에 통합할 수 있습니다.
형식화된 문자열을 사용자 정의하기 어려운 이유
"January 15, 2025"와 같은 형식화된 문자열을 받으면, 월이 끝나고 일이 시작되는 위치를 쉽게 식별할 수 없습니다. 로케일마다 구성 요소를 다른 순서로 배치합니다. 일부 로케일은 다른 구분 기호를 사용합니다. 이러한 문자열을 안정적으로 파싱하려면 Intl API에 이미 구현된 형식화 규칙을 복제하는 복잡한 로직이 필요합니다.
월 이름을 굵게 표시하는 캘린더 애플리케이션을 생각해 보세요. format()를 사용하면 다음과 같은 작업이 필요합니다.
- 월 이름을 나타내는 문자 감지
- 구성 요소 간의 공백 및 구두점 처리
- 로케일 전반의 다양한 월 형식 처리
- 날짜가 손상되지 않도록 문자열을 신중하게 파싱
이 접근 방식은 취약하고 오류가 발생하기 쉽습니다. 로케일 형식화 규칙이 변경되면 파싱 로직이 손상됩니다.
formatToParts() 메서드는 구성 요소를 별도로 제공하여 이 문제를 해결합니다. 로케일에 관계없이 어떤 부분이 무엇인지 정확히 알려주는 구조화된 데이터를 받습니다.
formatToParts를 사용하여 날짜 구성 요소 가져오기
formatToParts() 메서드는 반환 값을 제외하고 format()와 동일하게 작동합니다. 동일한 옵션으로 포매터를 생성한 다음 format() 대신 formatToParts()를 호출합니다.
const formatter = new Intl.DateTimeFormat("en-US", {
year: "numeric",
month: "long",
day: "numeric"
});
const date = new Date(2025, 0, 15);
const parts = formatter.formatToParts(date);
console.log(parts);
이는 객체 배열을 출력합니다:
[
{ type: "month", value: "January" },
{ type: "literal", value: " " },
{ type: "day", value: "15" },
{ type: "literal", value: ", " },
{ type: "year", value: "2025" }
]
각 객체는 해당 부분이 무엇을 나타내는지 식별하는 type 속성과 실제 문자열을 포함하는 value 속성을 포함합니다. 부분들은 포맷된 출력에서 나타나는 순서와 동일하게 표시됩니다.
모든 값을 함께 결합하여 이를 확인할 수 있습니다:
const formatted = parts.map(part => part.value).join("");
console.log(formatted);
// Output: "January 15, 2025"
연결된 부분들은 format()를 호출하는 것과 정확히 동일한 출력을 생성합니다.
부분 유형 이해하기
type 속성은 각 구성 요소를 식별합니다. 서로 다른 포맷 옵션은 서로 다른 부분 유형을 생성합니다.
기본 날짜 포맷의 경우:
const formatter = new Intl.DateTimeFormat("en-US", {
year: "numeric",
month: "long",
day: "numeric"
});
const date = new Date(2025, 0, 15);
const parts = formatter.formatToParts(date);
console.log(parts);
// [
// { type: "month", value: "January" },
// { type: "literal", value: " " },
// { type: "day", value: "15" },
// { type: "literal", value: ", " },
// { type: "year", value: "2025" }
// ]
month 유형은 월 이름 또는 숫자를 나타냅니다. day 유형은 월의 일을 나타냅니다. year 유형은 연도를 나타냅니다. literal 유형은 포매터가 삽입한 공백, 구두점 또는 기타 텍스트를 나타냅니다.
요일이 포함된 날짜의 경우:
const formatter = new Intl.DateTimeFormat("en-US", {
weekday: "long",
year: "numeric",
month: "long",
day: "numeric"
});
const date = new Date(2025, 0, 15);
const parts = formatter.formatToParts(date);
console.log(parts);
// [
// { type: "weekday", value: "Wednesday" },
// { type: "literal", value: ", " },
// { type: "month", value: "January" },
// { type: "literal", value: " " },
// { type: "day", value: "15" },
// { type: "literal", value: ", " },
// { type: "year", value: "2025" }
// ]
weekday 유형은 요일을 나타냅니다.
시간이 포함된 날짜의 경우:
const formatter = new Intl.DateTimeFormat("en-US", {
year: "numeric",
month: "long",
day: "numeric",
hour: "numeric",
minute: "numeric",
second: "numeric"
});
const date = new Date(2025, 0, 15, 14, 30, 45);
const parts = formatter.formatToParts(date);
console.log(parts);
// [
// { type: "month", value: "January" },
// { type: "literal", value: " " },
// { type: "day", value: "15" },
// { type: "literal", value: ", " },
// { type: "year", value: "2025" },
// { type: "literal", value: " at " },
// { type: "hour", value: "2" },
// { type: "literal", value: ":" },
// { type: "minute", value: "30" },
// { type: "literal", value: ":" },
// { type: "second", value: "45" },
// { type: "literal", value: " " },
// { type: "dayPeriod", value: "PM" }
// ]
hour, minute, second 유형은 시간 구성 요소를 나타냅니다. dayPeriod 유형은 12시간 형식에서 오전 또는 오후를 나타냅니다.
날짜 부분에 사용자 정의 스타일 적용하기
formatToParts()의 주요 사용 사례는 서로 다른 구성 요소에 서로 다른 스타일을 적용하는 것입니다. 부분 배열을 처리하여 특정 유형을 HTML 요소로 래핑할 수 있습니다.
월 이름을 굵게 표시하기:
const formatter = new Intl.DateTimeFormat("en-US", {
year: "numeric",
month: "long",
day: "numeric"
});
const date = new Date(2025, 0, 15);
const parts = formatter.formatToParts(date);
const html = parts
.map(part => {
if (part.type === "month") {
return `<strong>${part.value}</strong>`;
}
return part.value;
})
.join("");
console.log(html);
// Output: "<strong>January</strong> 15, 2025"
이 방식은 모든 마크업 언어에서 작동합니다. parts 배열을 처리하여 HTML, JSX 또는 기타 형식을 생성할 수 있습니다.
연도를 다르게 스타일링하기:
const formatter = new Intl.DateTimeFormat("en-US", {
year: "numeric",
month: "long",
day: "numeric"
});
const date = new Date(2025, 0, 15);
const parts = formatter.formatToParts(date);
const html = parts
.map(part => {
if (part.type === "year") {
return `<span class="text-gray-500">${part.value}</span>`;
}
return part.value;
})
.join("");
console.log(html);
// Output: "January 15, <span class="text-gray-500">2025</span>"
이 패턴은 서로 다른 구성 요소에 다른 시각적 강조가 필요한 달력 표시에서 일반적으로 사용됩니다.
여러 스타일을 사용한 사용자 정의 날짜 표시 구축
복잡한 인터페이스는 종종 여러 스타일링 규칙을 결합합니다. 서로 다른 part 유형에 동시에 다른 클래스나 요소를 적용할 수 있습니다.
const formatter = new Intl.DateTimeFormat("en-US", {
weekday: "long",
year: "numeric",
month: "long",
day: "numeric"
});
const date = new Date(2025, 0, 15);
const parts = formatter.formatToParts(date);
const html = parts
.map(part => {
switch (part.type) {
case "weekday":
return `<span class="weekday">${part.value}</span>`;
case "month":
return `<span class="month">${part.value}</span>`;
case "day":
return `<span class="day">${part.value}</span>`;
case "year":
return `<span class="year">${part.value}</span>`;
case "literal":
return `<span class="literal">${part.value}</span>`;
default:
return part.value;
}
})
.join("");
console.log(html);
// Output: "<span class="weekday">Wednesday</span><span class="literal">, </span><span class="month">January</span><span class="literal"> </span><span class="day">15</span><span class="literal">, </span><span class="year">2025</span>"
이러한 세밀한 제어를 통해 각 구성 요소에 대한 정확한 스타일링이 가능합니다. 그런 다음 CSS를 사용하여 각 클래스를 다르게 스타일링할 수 있습니다.
사용자 정의 날짜 레이아웃 만들기
표준 로케일 형식과 다른 사용자 정의 레이아웃으로 날짜 구성 요소를 재배열할 수 있습니다. 특정 부분을 추출하고 원하는 순서로 구성하세요.
const formatter = new Intl.DateTimeFormat("en-US", {
year: "numeric",
month: "long",
day: "numeric"
});
const date = new Date(2025, 0, 15);
const parts = formatter.formatToParts(date);
const day = parts.find(p => p.type === "day").value;
const month = parts.find(p => p.type === "month").value;
const year = parts.find(p => p.type === "year").value;
const customLayout = `
<div class="date-card">
<div class="day-large">${day}</div>
<div class="month-small">${month}</div>
<div class="year-small">${year}</div>
</div>
`;
console.log(customLayout);
이렇게 하면 일이 눈에 띄게 표시되고 그 뒤에 월과 연도가 표시되는 세로 카드 레이아웃이 생성됩니다. 레이아웃이 표준 형식과 다르더라도 구성 요소는 적절하게 현지화된 상태로 유지됩니다.
사용 가능한 모든 part 유형
type 속성은 사용된 포맷 옵션에 따라 다음 값을 가질 수 있습니다:
weekday: 월요일 또는 월과 같은 요일era: BC, AD 또는 BCE와 같은 연대 표시year: 2025와 같은 연도month: 1월 또는 01과 같은 월 이름 또는 숫자day: 15와 같은 월의 일dayPeriod: 오전 또는 오후 또는 기타 로케일별 일 기간hour: 14 또는 2와 같은 시간minute: 30과 같은 분second: 45와 같은 초fractionalSecond: 밀리초 또는 기타 소수 초timeZoneName: PST 또는 태평양 표준시와 같은 시간대 이름literal: 포맷에 의해 추가된 공백, 구두점 또는 기타 텍스트relatedYear: 대체 달력 시스템의 그레고리력 연도yearName: 일부 달력 시스템의 명명된 연도unknown: 인식되지 않은 토큰
모든 형식 옵션이 모든 부분 유형을 생성하는 것은 아닙니다. 받게 되는 부분은 날짜 값과 포매터 구성에 따라 달라집니다.
연호 표시가 있는 날짜:
const formatter = new Intl.DateTimeFormat("en-US", {
year: "numeric",
era: "short"
});
const date = new Date(-100, 0, 1);
const parts = formatter.formatToParts(date);
console.log(parts);
// [
// { type: "year", value: "101" },
// { type: "literal", value: " " },
// { type: "era", value: "BC" }
// ]
시간대가 있는 날짜:
const formatter = new Intl.DateTimeFormat("en-US", {
year: "numeric",
month: "long",
day: "numeric",
hour: "numeric",
minute: "numeric",
timeZoneName: "short"
});
const date = new Date(2025, 0, 15, 14, 30);
const parts = formatter.formatToParts(date);
console.log(parts);
// Parts will include { type: "timeZoneName", value: "PST" } or similar
소수 초가 있는 날짜:
const formatter = new Intl.DateTimeFormat("en-US", {
hour: "numeric",
minute: "numeric",
second: "numeric",
fractionalSecondDigits: 3
});
const date = new Date(2025, 0, 15, 14, 30, 45, 123);
const parts = formatter.formatToParts(date);
// Parts will include { type: "fractionalSecond", value: "123" }
조건부로 날짜 구성 요소 강조하기
일부 애플리케이션은 비즈니스 로직에 따라 특정 날짜 구성 요소를 강조 표시합니다. formatToParts()를 사용하면 적절한 형식을 유지하면서 날짜 값에 따라 스타일을 적용할 수 있습니다.
const formatter = new Intl.DateTimeFormat("en-US", {
year: "numeric",
month: "long",
day: "numeric"
});
function formatDateWithHighlight(date) {
const parts = formatter.formatToParts(date);
const isWeekend = date.getDay() === 0 || date.getDay() === 6;
const html = parts
.map(part => {
if (part.type === "day" && isWeekend) {
return `<span class="text-blue-600 font-bold">${part.value}</span>`;
}
return part.value;
})
.join("");
return html;
}
const saturday = new Date(2025, 0, 18);
console.log(formatDateWithHighlight(saturday));
// Output: "January <span class="text-blue-600 font-bold">18</span>, 2025"
const monday = new Date(2025, 0, 13);
console.log(formatDateWithHighlight(monday));
// Output: "January 13, 2025"
날짜는 로케일에 맞는 적절한 형식을 받으며 비즈니스 로직에 따라 조건부 스타일이 적용됩니다.
접근 가능한 날짜 표시 만들기
formatToParts()를 사용하여 형식화된 날짜에 접근성 속성을 추가할 수 있습니다. 이를 통해 스크린 리더가 값을 올바르게 읽을 수 있습니다.
const formatter = new Intl.DateTimeFormat("en-US", {
year: "numeric",
month: "long",
day: "numeric"
});
function formatAccessibleDate(date) {
const parts = formatter.formatToParts(date);
const formatted = parts.map(part => part.value).join("");
const isoDate = date.toISOString().split('T')[0];
return `<time datetime="${isoDate}">${formatted}</time>`;
}
const date = new Date(2025, 0, 15);
console.log(formatAccessibleDate(date));
// Output: "<time datetime="2025-01-15">January 15, 2025</time>"
이렇게 하면 스크린 리더가 날짜를 올바르게 읽을 수 있으며 화면에는 로케일에 맞게 형식화된 버전이 표시됩니다.
부분이 로케일별 형식을 유지하는 방법
parts 배열은 로케일별 형식 규칙을 자동으로 유지합니다. 로케일마다 구성 요소를 다른 순서로 배치하고 다른 형식을 사용하지만, formatToParts()가 이러한 차이를 처리합니다.
const usFormatter = new Intl.DateTimeFormat("en-US", {
year: "numeric",
month: "long",
day: "numeric"
});
const date = new Date(2025, 0, 15);
console.log(usFormatter.formatToParts(date));
// [
// { type: "month", value: "January" },
// { type: "literal", value: " " },
// { type: "day", value: "15" },
// { type: "literal", value: ", " },
// { type: "year", value: "2025" }
// ]
const ukFormatter = new Intl.DateTimeFormat("en-GB", {
year: "numeric",
month: "long",
day: "numeric"
});
console.log(ukFormatter.formatToParts(date));
// [
// { type: "day", value: "15" },
// { type: "literal", value: " " },
// { type: "month", value: "January" },
// { type: "literal", value: " " },
// { type: "year", value: "2025" }
// ]
영국식 형식은 일을 월 앞에 배치합니다. 스타일 코드는 로케일에 관계없이 동일한 방식으로 부분 배열을 처리하며 형식은 자동으로 조정됩니다.
const jpFormatter = new Intl.DateTimeFormat("ja-JP", {
year: "numeric",
month: "long",
day: "numeric"
});
console.log(jpFormatter.formatToParts(date));
// [
// { type: "year", value: "2025" },
// { type: "literal", value: "年" },
// { type: "month", value: "1月" },
// { type: "day", value: "15" },
// { type: "literal", value: "日" }
// ]
일본식 형식은 다른 순서를 사용하며 年(년) 및 日(일)과 같은 문자 리터럴을 포함합니다. 부분 배열은 이러한 로케일별 규칙을 자동으로 반영합니다.
formatToParts를 프레임워크 컴포넌트와 결합하기
React와 같은 최신 프레임워크는 formatToParts()를 사용하여 컴포넌트를 효율적으로 구축할 수 있습니다.
function DateDisplay({ date, locale, options }) {
const formatter = new Intl.DateTimeFormat(locale, options);
const parts = formatter.formatToParts(date);
return (
<span className="date-display">
{parts.map((part, index) => {
if (part.type === "month") {
return <strong key={index}>{part.value}</strong>;
}
if (part.type === "year") {
return <span key={index} className="text-sm text-gray-500">{part.value}</span>;
}
return <span key={index}>{part.value}</span>;
})}
</span>
);
}
이 컴포넌트는 모든 로케일에 대해 적절한 형식을 유지하면서 다른 부분에 다른 스타일을 적용합니다.
formatToParts와 format 중 언제 무엇을 사용할지
커스터마이징 없이 간단한 형식화된 문자열이 필요한 경우 format()를 사용하세요. 이는 대부분의 날짜 표시에서 일반적인 경우입니다.
formatToParts()는 다음이 필요한 경우 사용하세요:
- 날짜의 각 부분에 다른 스타일 적용
- 형식화된 날짜로 HTML 또는 JSX 구축
- 특정 구성 요소에 속성 또는 메타데이터 추가
- 날짜 구성 요소를 사용자 정의 레이아웃으로 재배열
- 형식화된 날짜를 복잡한 레이아웃에 통합
- 형식화된 출력을 프로그래밍 방식으로 처리
formatToParts() 메서드는 단일 문자열 대신 객체 배열을 생성하기 때문에 format()보다 약간 더 많은 오버헤드가 있습니다. 이 차이는 일반적인 애플리케이션에서는 무시할 수 있지만, 초당 수천 개의 날짜를 형식화하는 경우 format()가 더 나은 성능을 제공합니다.
대부분의 애플리케이션에서는 성능 문제보다 스타일링 요구 사항에 따라 선택하세요. 출력을 커스터마이징할 필요가 없다면 format()를 사용하세요. 커스텀 스타일링이나 마크업이 필요한 경우 formatToParts()를 사용하세요.