사용자 로케일에 맞춰 시간 형식을 지정하는 방법
JavaScript를 사용하여 각 사용자의 지역 규칙에 따라 시간을 표시하세요
소개
시간은 전 세계적으로 다르게 표시됩니다. 미국인들은 일반적으로 오후 3시 30분을 3:30 PM로 표시하는 반면, 대부분의 유럽인들은 15:30를 기대합니다. 시간 형식을 하드코딩하면 모든 사용자가 동일한 규칙을 따른다고 가정하게 됩니다.
익숙하지 않은 형식으로 시간을 표시하면 혼란이 발생합니다. 24시간 형식에 익숙한 사용자가 3:30 PM를 보면 오전인지 오후인지 이해하기 위해 머릿속으로 변환해야 합니다. 이러한 인지 부하는 애플리케이션의 모든 시간에 걸쳐 누적됩니다.
JavaScript는 시간 형식을 자동으로 처리하기 위해 Intl.DateTimeFormat API를 제공합니다. 이 레슨에서는 시간 형식이 문화권마다 다른 이유, API 작동 방식, 그리고 모든 로케일에 대해 시간을 올바르게 형식화하는 방법을 설명합니다.
로케일에 따라 시간 형식이 다른 이유
각 지역은 시간 표시에 대한 서로 다른 규칙을 발전시켰습니다. 이러한 규칙은 역사적 관행, 교육 시스템, 문화적 선호도를 반영합니다. 보편적인 단일 형식은 존재하지 않습니다.
미국, 캐나다, 호주, 필리핀에서는 AM 및 PM 표시와 함께 12시간 형식을 사용합니다. 오후 3시 30분은 3:30 PM로 표시됩니다.
대부분의 유럽 국가, 라틴 아메리카, 아시아에서는 AM 또는 PM 표시 없이 24시간 형식을 사용합니다. 동일한 시간이 15:30로 표시됩니다.
시와 분 사이의 구분 문자도 다릅니다. 영어권 국가에서는 콜론을 사용하지만, 일부 로케일에서는 마침표나 다른 구두점을 사용합니다.
AM과 PM이 표시되는 방식도 다릅니다. 영어는 AM와 PM를 사용하고, 스페인어는 a.m.와 p.m.를 사용하며, 일부 로케일에서는 이러한 표시를 시간 뒤가 아닌 앞에 배치합니다.
시간을 표시할 때는 시간 형식과 특정 형식 규칙 모두에 대한 사용자의 기대에 부합해야 합니다.
Intl.DateTimeFormat을 사용한 시간 형식 지정
Intl.DateTimeFormat 생성자는 로케일별 규칙을 적용하는 포맷터를 생성합니다. 시간을 형식화하려면 첫 번째 인수로 로케일 식별자를 전달하고 두 번째 인수에서 시간 관련 옵션을 지정합니다.
const formatter = new Intl.DateTimeFormat('en-US', {
hour: 'numeric',
minute: 'numeric'
});
const date = new Date('2025-03-15T15:30:00');
console.log(formatter.format(date));
// Output: "3:30 PM"
이것은 시간과 분을 표시하는 미국 영어용 포맷터를 생성합니다. hour 및 minute 옵션은 포맷터에게 이러한 구성 요소를 포함하도록 지시합니다. format() 메서드는 Date 객체를 적절한 형식의 문자열로 변환합니다.
Date 생성자는 2025-03-15T15:30:00와 같은 ISO 8601 날짜/시간 문자열을 받습니다. 이는 2025년 3월 15일 오후 3시 30분을 나타내는 Date 객체를 생성합니다. 그런 다음 포매터가 이를 로케일별 시간 문자열로 변환합니다.
다양한 로케일에 대해 동일한 시간 형식 지정
생성자에 전달되는 로케일 식별자를 변경하여 다양한 로케일에 대해 동일한 시간을 형식 지정할 수 있습니다.
const date = new Date('2025-03-15T15:30:00');
const usFormatter = new Intl.DateTimeFormat('en-US', {
hour: 'numeric',
minute: 'numeric'
});
console.log(usFormatter.format(date));
// Output: "3:30 PM"
const gbFormatter = new Intl.DateTimeFormat('en-GB', {
hour: 'numeric',
minute: 'numeric'
});
console.log(gbFormatter.format(date));
// Output: "15:30"
const deFormatter = new Intl.DateTimeFormat('de-DE', {
hour: 'numeric',
minute: 'numeric'
});
console.log(deFormatter.format(date));
// Output: "15:30"
const frFormatter = new Intl.DateTimeFormat('fr-FR', {
hour: 'numeric',
minute: 'numeric'
});
console.log(frFormatter.format(date));
// Output: "15:30"
각 포매터는 서로 다른 규칙을 적용합니다. 미국 포매터는 AM/PM이 포함된 12시간 형식을 사용합니다. 영국, 독일 및 프랑스 포매터는 모두 AM/PM 표시 없이 24시간 형식을 사용합니다.
각 로케일이 어떤 형식을 사용하는지 알 필요가 없습니다. API는 로케일 식별자를 기반으로 이러한 세부 사항을 자동으로 처리합니다.
시간 표시에 초 포함
second 옵션을 추가하여 시와 분과 함께 초를 표시할 수 있습니다.
const formatter = new Intl.DateTimeFormat('en-US', {
hour: 'numeric',
minute: 'numeric',
second: 'numeric'
});
const date = new Date('2025-03-15T15:30:45');
console.log(formatter.format(date));
// Output: "3:30:45 PM"
second 옵션은 hour 및 minute와 동일한 방식으로 작동합니다. 출력에 초를 포함하려면 'numeric'로 설정하세요.
2-digit으로 자릿수 패딩 제어
hour, minute, second 옵션은 두 가지 값을 받습니다: 'numeric'와 '2-digit'. 'numeric' 값은 패딩 없이 숫자를 표시하고, '2-digit'는 항상 앞에 0을 붙여 두 자리 숫자로 표시합니다.
const date = new Date('2025-03-15T09:05:03');
const numericFormatter = new Intl.DateTimeFormat('en-US', {
hour: 'numeric',
minute: 'numeric',
second: 'numeric'
});
console.log(numericFormatter.format(date));
// Output: "9:05:03 AM"
const twoDigitFormatter = new Intl.DateTimeFormat('en-US', {
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
});
console.log(twoDigitFormatter.format(date));
// Output: "09:05:03 AM"
숫자 포매터는 시간을 한 자리 숫자로 9:05:03 AM로 표시합니다. 두 자리 포매터는 시간을 앞에 0을 붙여 09:05:03 AM로 표시합니다. 분과 초는 설정과 관계없이 일반적으로 패딩되므로 두 자리 숫자로 표시됩니다.
12시간 또는 24시간 형식 강제 적용
기본적으로 API는 로케일에서 선호하는 시간 형식을 사용합니다. hour12 옵션으로 이를 재정의할 수 있습니다.
const date = new Date('2025-03-15T15:30:00');
const hour12Formatter = new Intl.DateTimeFormat('en-GB', {
hour: 'numeric',
minute: 'numeric',
hour12: true
});
console.log(hour12Formatter.format(date));
// Output: "3:30 pm"
const hour24Formatter = new Intl.DateTimeFormat('en-US', {
hour: 'numeric',
minute: 'numeric',
hour12: false
});
console.log(hour24Formatter.format(date));
// Output: "15:30"
hour12: true로 설정하면 일반적으로 24시간 형식을 사용하는 로케일에서도 12시간 형식이 강제됩니다. hour12: false로 설정하면 일반적으로 12시간 형식을 사용하는 로케일에서도 24시간 형식이 강제됩니다.
로케일은 여전히 구두점 및 간격과 같은 다른 형식 세부 사항을 결정합니다. hour12: true를 사용하는 영국 포매터는 소문자 pm로 3:30 pm를 표시하는 반면, 미국 포매터는 대문자 PM로 3:30 PM를 표시합니다.
사용자 로케일에 맞춰 시간 형식 지정
특정 로케일을 하드코딩하는 대신 브라우저에서 사용자가 선호하는 언어를 사용할 수 있습니다. navigator.language 속성은 사용자의 최우선 언어 기본 설정을 반환합니다.
const userLocale = navigator.language;
const formatter = new Intl.DateTimeFormat(userLocale, {
hour: 'numeric',
minute: 'numeric'
});
const date = new Date('2025-03-15T15:30:00');
console.log(formatter.format(date));
// Output varies by user's locale
// For en-US: "3:30 PM"
// For en-GB: "15:30"
// For de-DE: "15:30"
// For fr-FR: "15:30"
이 접근 방식은 사용자가 수동으로 로케일을 선택할 필요 없이 각 사용자의 기대에 따라 시간을 표시합니다. 브라우저가 언어 기본 설정을 제공하고 Intl API가 적절한 형식 규칙을 적용합니다.
폴백 동작을 활성화하기 위해 선호하는 언어의 전체 배열을 전달할 수도 있습니다.
const formatter = new Intl.DateTimeFormat(navigator.languages, {
hour: 'numeric',
minute: 'numeric'
});
const date = new Date('2025-03-15T15:30:00');
console.log(formatter.format(date));
API는 배열에서 지원하는 첫 번째 로케일을 사용합니다. 이는 사용자의 최우선 기본 설정을 사용할 수 없을 때 더 나은 폴백 처리를 제공합니다.
형식을 지정할 시간 생성
여러 가지 방법으로 시간 정보가 포함된 Date 객체를 생성할 수 있습니다. 가장 신뢰할 수 있는 접근 방식은 ISO 8601 날짜/시간 문자열을 사용하는 것입니다.
const time1 = new Date('2025-03-15T09:00:00');
const time2 = new Date('2025-03-15T15:30:00');
const time3 = new Date('2025-03-15T23:45:30');
const formatter = new Intl.DateTimeFormat('en-US', {
hour: 'numeric',
minute: 'numeric'
});
console.log(formatter.format(time1));
// Output: "9:00 AM"
console.log(formatter.format(time2));
// Output: "3:30 PM"
console.log(formatter.format(time3));
// Output: "11:45 PM"
ISO 8601 날짜/시간 문자열은 YYYY-MM-DDTHH:MM:SS 형식을 사용합니다. T는 날짜와 시간을 구분합니다. 이 형식은 명확하며 모든 로케일과 시간대에서 일관되게 작동합니다.
타임스탬프에서 시간 형식 지정
Unix 타임스탬프에서 Date 객체를 생성할 수도 있습니다. Unix 타임스탬프는 1970년 1월 1일 UTC 이후의 밀리초 수를 나타냅니다.
const timestamp = 1710515400000; // March 15, 2025 at 3:30 PM
const date = new Date(timestamp);
const formatter = new Intl.DateTimeFormat('en-US', {
hour: 'numeric',
minute: 'numeric'
});
console.log(formatter.format(date));
// Output: "3:30 PM"
이 방식은 API, 데이터베이스 또는 시간을 숫자로 표현하는 다른 시스템에서 타임스탬프를 받을 때 유용합니다.
Date 객체를 먼저 생성하지 않고 타임스탬프를 format() 메서드에 직접 전달할 수도 있습니다.
const formatter = new Intl.DateTimeFormat('en-US', {
hour: 'numeric',
minute: 'numeric'
});
const timestamp = 1710515400000;
console.log(formatter.format(timestamp));
// Output: "3:30 PM"
API는 Date 객체와 타임스탬프를 모두 허용합니다. 코드에 더 적합한 방식을 사용하세요.
현재 시간 형식 지정
현재 시간을 형식 지정하려면 인수 없이 Date 객체를 생성합니다. 이렇게 하면 현재 시점을 나타내는 Date 객체가 생성됩니다.
const formatter = new Intl.DateTimeFormat('en-US', {
hour: 'numeric',
minute: 'numeric',
second: 'numeric'
});
const now = new Date();
console.log(formatter.format(now));
// Output: "3:45:12 PM" (or current time when run)
Date.now()를 직접 전달할 수도 있으며, 이는 현재 타임스탬프를 숫자로 반환합니다.
const formatter = new Intl.DateTimeFormat('en-US', {
hour: 'numeric',
minute: 'numeric',
second: 'numeric'
});
console.log(formatter.format(Date.now()));
// Output: "3:45:12 PM" (or current time when run)
두 방식 모두 동일한 결과를 생성합니다.
성능을 위한 포매터 재사용
새로운 Intl.DateTimeFormat 인스턴스를 생성하려면 로케일 데이터를 로드하고 옵션을 처리해야 합니다. 동일한 로케일과 설정으로 여러 번 포맷해야 하는 경우 포매터를 한 번 생성하고 재사용하세요.
const formatter = new Intl.DateTimeFormat('en-US', {
hour: 'numeric',
minute: 'numeric'
});
const times = [
new Date('2025-03-15T09:00:00'),
new Date('2025-03-15T12:30:00'),
new Date('2025-03-15T18:45:00')
];
times.forEach(time => {
console.log(formatter.format(time));
});
// Output:
// "9:00 AM"
// "12:30 PM"
// "6:45 PM"
이 방식은 각 시간마다 새 포매터를 생성하는 것보다 효율적입니다. 수백 또는 수천 개의 시간 값이 있는 배열을 형식 지정할 때 성능 차이가 두드러집니다.
템플릿에서 시간 형식 지정
사용자에게 시간을 표시하는 모든 곳에서 Intl.DateTimeFormat를 사용할 수 있습니다. 여기에는 HTML 템플릿에 포맷된 시간 삽입, 테이블에 시간 표시 또는 사용자 인터페이스에 타임스탬프 표시가 포함됩니다.
const formatter = new Intl.DateTimeFormat(navigator.language, {
hour: 'numeric',
minute: 'numeric'
});
const eventStart = new Date('2025-03-15T14:00:00');
const eventEnd = new Date('2025-03-15T16:30:00');
document.getElementById('start-time').textContent = formatter.format(eventStart);
document.getElementById('end-time').textContent = formatter.format(eventEnd);
형식화된 문자열은 다른 문자열 값과 동일하게 작동합니다. 텍스트 콘텐츠, 속성 또는 사용자에게 정보를 표시하는 기타 컨텍스트에 삽입할 수 있습니다.