JavaScript에서 형식이 지정된 날짜의 개별 부분을 가져오는 방법
formatToParts()를 사용하여 로케일 형식이 지정된 날짜의 각 구성 요소에 개별적으로 접근하세요
소개
'format()' 메서드는 "January 15, 2025" 또는 "15/01/2025"와 같은 완전히 형식화된 문자열을 반환합니다. 이는 단순 표시에는 잘 작동하지만, 개별 부분을 다르게 스타일링할 수 없습니다. 월 이름을 굵게 표시하거나, 연도를 다른 색상으로 지정하거나, 특정 구성 요소에 사용자 정의 마크업을 적용할 수 없습니다.
자바스크립트는 이 문제를 해결하기 위해 '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);
// 출력: "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시간 형식에서 AM 또는 PM을 나타냅니다.
날짜 부분에 사용자 정의 스타일 적용하기
'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);
// 출력: "<strong>January</strong> 15, 2025"
이 접근 방식은 모든 마크업 언어에서 작동합니다. 부분 배열을 처리하여 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);
// 출력: "January 15, <span class="text-gray-500">2025</span>"
이 패턴은 다양한 구성 요소에 서로 다른 시각적 강조가 필요한 캘린더 디스플레이에서 일반적으로 사용됩니다.
다양한 스타일을 사용한 사용자 정의 날짜 표시 구축하기
복잡한 인터페이스는 종종 여러 스타일링 규칙을 결합합니다. 서로 다른 부분 유형에 동시에 다양한 클래스나 요소를 적용할 수 있습니다.
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);
// 출력: "<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);
이렇게 하면 날짜가 눈에 띄게 표시되고 그 뒤에 월과 연도가 표시되는 세로 카드 레이아웃이 생성됩니다. 레이아웃이 표준 형식과 다르더라도 구성 요소는 올바르게 현지화된 상태로 유지됩니다.
사용 가능한 모든 부분 유형
사용된 형식 옵션에 따라 type 속성은 다음 값을 가질 수 있습니다:
weekday: Monday 또는 Mon과 같은 요일era: BC, AD 또는 BCE와 같은 시대 표시기year: 2025와 같은 연도month: January 또는 01과 같은 월 이름 또는 숫자day: 15와 같은 월의 일dayPeriod: AM 또는 PM 또는 기타 로케일별 일 기간hour: 14 또는 2와 같은 시간minute: 30과 같은 분second: 45와 같은 초fractionalSecond: 밀리초 또는 기타 소수 초timeZoneName: PST 또는 Pacific Standard Time과 같은 시간대 이름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));
// 출력: "January <span class="text-blue-600 font-bold">18</span>, 2025"
const monday = new Date(2025, 0, 13);
console.log(formatDateWithHighlight(monday));
// 출력: "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));
// 출력: "<time datetime="2025-01-15">January 15, 2025</time>"
이렇게 하면 화면에는 로케일 형식의 버전이 표시되는 동시에 스크린 리더가 날짜를 올바르게 읽을 수 있습니다.
구성요소가 로케일별 형식을 유지하는 방법
구성요소 배열은 로케일별 형식 규칙을 자동으로 유지합니다. 다양한 로케일은 구성요소를 다른 순서로 배치하고 다른 형식을 사용하지만, 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()를 사용하세요.