유효한 시간대 식별자 목록을 가져오는 방법
드롭다운 구축 및 사용자 입력 검증을 위해 JavaScript에서 지원되는 모든 IANA 시간대 식별자 검색
소개
사용자가 시간대를 선택할 수 있는 기능을 구축할 때, 어떤 시간대 식별자가 유효한지 알아야 합니다. 뉴욕에 있는 사용자는 America/New_York을 선택해야 하고, 도쿄에 있는 사용자는 Asia/Tokyo를 선택해야 합니다. 시간대 목록을 하드코딩하면 여러 문제가 발생합니다.
첫째, 목록이 구식이 됩니다. 정부가 일광 절약 시간제 규칙을 수정하거나 새로운 시간대를 만들 때 시간대 정의가 변경됩니다. 둘째, 다양한 JavaScript 환경은 서로 다른 시간대를 지원합니다. Chrome에서 작동하는 시간대가 오래된 브라우저나 Node.js 버전에서는 작동하지 않을 수 있습니다. 셋째, 수백 개의 시간대 문자열을 수동으로 유지 관리하면 오타와 불일치가 발생할 가능성이 있습니다.
JavaScript는 현재 환경이 지원하는 모든 시간대 식별자를 검색하기 위한 Intl.supportedValuesOf() 메서드를 제공합니다. 이를 통해 애플리케이션이 올바르게 작동하는 시간대만 제공하고 시간대 데이터베이스의 변경 사항을 최신 상태로 유지할 수 있습니다.
시간대 식별자란
시간대 식별자는 일관된 시간 규칙을 가진 지리적 영역을 나타내는 표준화된 문자열입니다. 이는 전 세계의 시간대와 일광 절약 시간제 변경 사항을 추적하는 국제 기구가 유지 관리하는 포괄적인 목록인 IANA 시간대 데이터베이스에서 제공됩니다.
식별자는 다양한 시스템에서 명확하고 안정적으로 사용할 수 있는 특정 형식을 사용합니다. 이 형식을 이해하면 시간대를 효과적으로 다룰 수 있습니다.
IANA 시간대 식별자 형식 이해하기
IANA 시간대 식별자는 지역/위치 패턴을 따릅니다. 여기서 지역은 대륙이나 해양을 나타내고, 위치는 해당 지역 내의 도시나 지역을 나타냅니다.
const examples = [
'America/New_York',
'Europe/London',
'Asia/Tokyo',
'Australia/Sydney',
'Pacific/Auckland'
];
지역은 다음에 해당합니다:
America: 북미와 남미Europe: 유럽 지역Asia: 아시아 지역Africa: 아프리카 지역Australia: 호주 지역Pacific: 태평양 섬Atlantic: 대서양 섬Indian: 인도양 섬Antarctica: 남극 연구 기지
위치는 일반적으로 시간대에서 가장 크거나 대표적인 도시를 나타냅니다. 뉴욕은 미국의 동부 시간대를 나타냅니다. 도쿄는 일본을 나타냅니다. 시드니는 호주의 동부 시간대를 나타냅니다.
일부 식별자는 더 큰 지역 내의 지역을 위해 세 부분을 포함합니다:
const detailedExamples = [
'America/Indiana/Indianapolis',
'America/Kentucky/Louisville',
'America/North_Dakota/Center'
];
이러한 다중 부분 식별자는 같은 국가 내에서 다른 시간 규칙을 따르는 지역을 구분합니다.
데이터베이스는 도시 이름에 공백 대신 밑줄을 사용합니다:
const underscoreExamples = [
'America/New_York', // "New York"가 아님
'America/Los_Angeles', // "Los Angeles"가 아님
'Asia/Ho_Chi_Minh' // "Ho Chi Minh"이 아님
];
이 형식은 구문 분석 문제를 일으킬 수 있는 특수 문자 없이 식별자가 단일 토큰으로 작동하도록 보장합니다.
식별자가 약어 대신 도시를 사용하는 이유
동부 표준시에는 EST, 태평양 표준시에는 PST와 같은 약어를 사용할 것으로 예상할 수 있습니다. 그러나 이러한 약어는 모호합니다. EST는 북미의 동부 표준시를 의미하지만 호주 동부 표준시도 의미합니다. CST는 중부 표준시, 중국 표준시 또는 쿠바 표준시를 의미할 수 있습니다.
도시 기반 식별자는 모호하지 않게 유지됩니다. America/New_York는 항상 컨텍스트에 관계없이 동일한 장소와 시간 규칙을 참조합니다.
또한 약어는 일광 절약 시간 전환을 포착하지 못합니다. EST는 EDT(동부 일광 절약 시간)가 아닌 표준 시간만 나타냅니다. America/New_York 식별자는 날짜에 따라 표준 시간과 일광 절약 시간을 자동으로 처리합니다.
지원되는 모든 시간대 식별자 가져오기
'timeZone' 매개변수를 사용한 Intl.supportedValuesOf() 메서드는 JavaScript 환경에서 지원하는 모든 시간대 식별자의 배열을 반환합니다.
const timeZones = Intl.supportedValuesOf('timeZone');
console.log(timeZones.length);
// 출력: 400개 이상
console.log(timeZones.slice(0, 10));
// 출력: [
// "Africa/Abidjan",
// "Africa/Accra",
// "Africa/Addis_Ababa",
// "Africa/Algiers",
// "Africa/Asmera",
// "Africa/Bamako",
// "Africa/Bangui",
// "Africa/Banjul",
// "Africa/Bissau",
// "Africa/Blantyre"
// ]
이 메서드는 중복 없이 알파벳 순서로 식별자를 반환합니다. 정확한 목록은 JavaScript 환경에 따라 다르지만, 최신 브라우저와 Node.js 버전은 400개 이상의 시간대를 지원합니다.
배열의 각 식별자는 Intl.DateTimeFormat과 함께 사용하여 해당 시간대의 날짜와 시간을 형식화할 수 있습니다:
const timeZone = timeZones[0]; // "Africa/Abidjan"
const date = new Date('2025-10-15T12:00:00Z');
const formatter = new Intl.DateTimeFormat('en-US', {
timeZone: timeZone,
dateStyle: 'long',
timeStyle: 'short'
});
console.log(formatter.format(date));
// 출력: "October 15, 2025 at 12:00 PM"
이 메서드는 반환하는 모든 식별자가 Intl API와 올바르게 작동하도록 보장합니다.
시간대 선택기 구축하기
모든 시간대 식별자를 가져오는 가장 일반적인 사용 사례는 사용자가 시간대를 선택할 수 있는 드롭다운 또는 선택 요소를 구축하는 것입니다.
function buildTimeZoneSelector() {
const timeZones = Intl.supportedValuesOf('timeZone');
const select = document.createElement('select');
select.name = 'timeZone';
timeZones.forEach(timeZone => {
const option = document.createElement('option');
option.value = timeZone;
option.textContent = timeZone;
select.appendChild(option);
});
return select;
}
const selector = buildTimeZoneSelector();
document.body.appendChild(selector);
이 코드는 지원되는 모든 시간대에 대한 옵션이 있는 선택 요소를 생성합니다. 사용자는 목록을 스크롤하여 자신의 위치를 선택할 수 있습니다.
그러나 정렬되지 않은 400개 이상의 식별자 목록은 사용자 경험을 저하시킵니다. 사용자는 식별자가 어떻게 구성되어 있는지 이해하고 자신의 위치를 빠르게 찾을 수 있어야 합니다.
지역별 시간대 그룹화
대륙별로 시간대를 구성하면 목록을 더 쉽게 탐색할 수 있습니다. 각 식별자에서 지역을 추출하여 그에 따라 그룹화할 수 있습니다.
function groupTimeZonesByRegion() {
const timeZones = Intl.supportedValuesOf('timeZone');
const grouped = {};
timeZones.forEach(timeZone => {
const parts = timeZone.split('/');
const region = parts[0];
if (!grouped[region]) {
grouped[region] = [];
}
grouped[region].push(timeZone);
});
return grouped;
}
const grouped = groupTimeZonesByRegion();
console.log(Object.keys(grouped));
// 출력: [
// "Africa", "America", "Antarctica", "Arctic",
// "Asia", "Atlantic", "Australia", "Europe",
// "Indian", "Pacific", "Etc"
// ]
console.log(grouped['America'].slice(0, 5));
// 출력: [
// "America/Adak",
// "America/Anchorage",
// "America/Anguilla",
// "America/Antigua",
// "America/Araguaina"
// ]
이 함수는 각 식별자를 슬래시(/)로 분할하고 첫 번째 부분을 지역 키로 사용합니다. 이렇게 하면 각 지역에 시간대 배열이 포함된 객체가 생성됩니다.
이 그룹화된 데이터를 사용하여 optgroup 요소가 있는 더 체계적인 선택기를 구축할 수 있습니다:
function buildGroupedTimeZoneSelector() {
const grouped = groupTimeZonesByRegion();
const select = document.createElement('select');
select.name = 'timeZone';
Object.keys(grouped).sort().forEach(region => {
const optgroup = document.createElement('optgroup');
optgroup.label = region;
grouped[region].forEach(timeZone => {
const option = document.createElement('option');
option.value = timeZone;
option.textContent = timeZone.split('/').slice(1).join('/');
optgroup.appendChild(option);
});
select.appendChild(optgroup);
});
return select;
}
const groupedSelector = buildGroupedTimeZoneSelector();
document.body.appendChild(groupedSelector);
이렇게 하면 시간대가 지역별 제목 아래에 표시되는 선택 요소가 생성됩니다. 옵션 텍스트는 식별자의 도시 부분만 표시하여 목록을 더 읽기 쉽게 만듭니다.
지역별 시간대 필터링
때로는 특정 지역의 시간대만 필요할 수 있습니다. 예를 들어, 북미 사용자만을 대상으로 하는 애플리케이션은 미국 시간대만 표시할 수 있습니다.
function getTimeZonesForRegion(region) {
const timeZones = Intl.supportedValuesOf('timeZone');
return timeZones.filter(timeZone => timeZone.startsWith(`${region}/`));
}
const americanTimeZones = getTimeZonesForRegion('America');
console.log(americanTimeZones.length);
// Output: over 150
console.log(americanTimeZones.slice(0, 5));
// Output: [
// "America/Adak",
// "America/Anchorage",
// "America/Anguilla",
// "America/Antigua",
// "America/Araguaina"
// ]
이 함수는 전체 목록에서 지정된 지역으로 시작하는 식별자만 포함하도록 필터링합니다. 어떤 지역 이름으로든 호출하여 집중된 목록을 얻을 수 있습니다.
여러 지역에 대해 필터링할 수도 있습니다:
function getTimeZonesForRegions(regions) {
const timeZones = Intl.supportedValuesOf('timeZone');
return timeZones.filter(timeZone => {
return regions.some(region => timeZone.startsWith(`${region}/`));
});
}
const europeanAndAsianTimeZones = getTimeZonesForRegions(['Europe', 'Asia']);
console.log(europeanAndAsianTimeZones.length);
// Output: over 200
이는 모든 지역이 아닌 여러 지역을 서비스하는 애플리케이션에 유연성을 제공합니다.
특정 시간대 검색
사용자가 찾고자 하는 도시를 알고 있을 때, 이름으로 검색하면 빠르게 찾을 수 있습니다.
function searchTimeZones(query) {
const timeZones = Intl.supportedValuesOf('timeZone');
const lowerQuery = query.toLowerCase();
return timeZones.filter(timeZone => {
return timeZone.toLowerCase().includes(lowerQuery);
});
}
const newYorkResults = searchTimeZones('new_york');
console.log(newYorkResults);
// Output: ["America/New_York"]
const londonResults = searchTimeZones('london');
console.log(londonResults);
// Output: ["Europe/London"]
const tokyoResults = searchTimeZones('tokyo');
console.log(tokyoResults);
// Output: ["Asia/Tokyo"]
이 함수는 모든 시간대 식별자에 대해 대소문자를 구분하지 않는 검색을 수행합니다. 사용자는 도시 이름의 일부를 입력하여 일치하는 시간대를 찾을 수 있습니다.
더 나은 사용자 경험을 위해 부분 일치를 검색하고 공백을 처리할 수 있습니다:
function searchTimeZonesFlexible(query) {
const timeZones = Intl.supportedValuesOf('timeZone');
const normalizedQuery = query.toLowerCase().replace(/\s+/g, '_');
return timeZones.filter(timeZone => {
return timeZone.toLowerCase().includes(normalizedQuery);
});
}
const results = searchTimeZonesFlexible('new york');
console.log(results);
// Output: ["America/New_York"]
이 버전은 쿼리의 공백을 밑줄로 변환하여 시간대 식별자에 사용되는 형식과 일치시킵니다.
시간대 식별자 검증하기
사용자가 시간대 식별자를 입력으로 제공할 때, Intl.DateTimeFormat과 함께 사용하기 전에 해당 식별자가 유효한지 확인해야 합니다.
function isValidTimeZone(timeZone) {
const supportedTimeZones = Intl.supportedValuesOf('timeZone');
return supportedTimeZones.includes(timeZone);
}
console.log(isValidTimeZone('America/New_York'));
// 출력: true
console.log(isValidTimeZone('Europe/London'));
// 출력: true
console.log(isValidTimeZone('Invalid/TimeZone'));
// 출력: false
console.log(isValidTimeZone('EST'));
// 출력: false
이 함수는 주어진 문자열이 지원되는 시간대 목록에 포함되어 있는지 확인합니다. 식별자가 유효하지 않은 경우, 거부하거나 사용자에게 유효한 옵션 중에서 선택하도록 요청할 수 있습니다.
또한 식별자를 사용해보고 오류를 캐치하는 방법도 있습니다:
function validateTimeZoneByCatch(timeZone) {
try {
new Intl.DateTimeFormat('en-US', { timeZone });
return true;
} catch (error) {
return false;
}
}
console.log(validateTimeZoneByCatch('America/New_York'));
// 출력: true
console.log(validateTimeZoneByCatch('Invalid/TimeZone'));
// 출력: false
이 접근 방식은 작동하지만 지원되는 값 목록을 확인하는 것보다 효율성이 떨어집니다. 성능이 중요한 경우 지원되는 값 확인 방법을 사용하세요.
시간대의 현재 오프셋 표시하기
사용자들은 종종 시간대를 UTC로부터의 오프셋 관점에서 생각합니다. 각 시간대 이름과 함께 현재 오프셋을 표시하면 사용자가 시간 차이를 이해하는 데 도움이 됩니다.
function getTimeZoneOffset(timeZone) {
const date = new Date();
const formatter = new Intl.DateTimeFormat('en-US', {
timeZone,
timeZoneName: 'shortOffset'
});
const parts = formatter.formatToParts(date);
const offsetPart = parts.find(part => part.type === 'timeZoneName');
return offsetPart ? offsetPart.value : '';
}
const timeZones = [
'America/New_York',
'Europe/London',
'Asia/Tokyo',
'Australia/Sydney'
];
timeZones.forEach(timeZone => {
const offset = getTimeZoneOffset(timeZone);
console.log(`${timeZone}: ${offset}`);
});
// 출력:
// America/New_York: GMT-4
// Europe/London: GMT+1
// Asia/Tokyo: GMT+9
// Australia/Sydney: GMT+11
이 함수는 shortOffset 시간대 이름 스타일로 날짜를 포맷하고, 포맷된 부분에서 오프셋 부분을 추출합니다. 이를 통해 각 시간대가 UTC보다 몇 시간 앞서거나 뒤쳐져 있는지 보여줍니다.
일광 절약 시간제에 따라 오프셋이 변경된다는 점에 유의하세요. 같은 시간대도 겨울과 여름에 다른 오프셋을 보여줍니다:
const newYorkWinter = getTimeZoneOffset('America/New_York');
// 1월에: GMT-5
const newYorkSummer = getTimeZoneOffset('America/New_York');
// 7월에: GMT-4
이 함수가 반환하는 오프셋은 현재 날짜를 반영하므로, 연중 일광 절약 규칙이 변경됨에 따라 자동으로 업데이트됩니다.
오프셋이 포함된 완전한 시간대 선택기 구축하기
그룹화, 필터링 및 오프셋 표시를 결합하면 포괄적인 시간대 선택기를 만들 수 있습니다:
function buildCompleteTimeZoneSelector() {
const timeZones = Intl.supportedValuesOf('timeZone');
const select = document.createElement('select');
select.name = 'timeZone';
const grouped = {};
timeZones.forEach(timeZone => {
const region = timeZone.split('/')[0];
if (!grouped[region]) {
grouped[region] = [];
}
grouped[region].push(timeZone);
});
Object.keys(grouped).sort().forEach(region => {
const optgroup = document.createElement('optgroup');
optgroup.label = region;
grouped[region].forEach(timeZone => {
const offset = getTimeZoneOffset(timeZone);
const location = timeZone.split('/').slice(1).join('/');
const option = document.createElement('option');
option.value = timeZone;
option.textContent = `${location} (${offset})`;
optgroup.appendChild(option);
});
select.appendChild(optgroup);
});
return select;
}
const completeSelector = buildCompleteTimeZoneSelector();
document.body.appendChild(completeSelector);
이 선택기는 시간대를 지역별로 그룹화하고, 읽기 쉬운 위치 이름을 표시하며, 현재 UTC 오프셋을 포함합니다. 사용자는 지역별로 시간대를 빠르게 찾고 오프셋이 자신의 예상과 일치하는지 확인할 수 있습니다.
사용자의 현재 시간대 가져오기
지원되는 모든 시간대를 가져오는 것이 선택 인터페이스에 유용하지만, 기본값으로 사용할 사용자의 현재 시간대를 알고 싶을 때가 많습니다.
function getUserTimeZone() {
return Intl.DateTimeFormat().resolvedOptions().timeZone;
}
const userTimeZone = getUserTimeZone();
console.log(userTimeZone);
// 출력: "America/New_York" (또는 사용자의 실제 시간대)
이는 사용자 시스템 시간대에 대한 IANA 식별자를 반환합니다. 이를 사용하여 시간대 선택기에서 올바른 옵션을 미리 선택할 수 있습니다:
function buildTimeZoneSelectorWithDefault() {
const selector = buildCompleteTimeZoneSelector();
const userTimeZone = getUserTimeZone();
const options = selector.querySelectorAll('option');
options.forEach(option => {
if (option.value === userTimeZone) {
option.selected = true;
}
});
return selector;
}
const selectorWithDefault = buildTimeZoneSelectorWithDefault();
document.body.appendChild(selectorWithDefault);
이렇게 하면 사용자의 현재 시간대가 이미 선택된 선택기가 생성되어, 사용자가 자신의 위치를 확인할 때 마찰을 줄일 수 있습니다.
특수 시간대 처리하기
지원되는 시간대 목록에는 표준 Area/Location 패턴을 따르지 않는 일부 특수 식별자가 포함되어 있습니다.
const timeZones = Intl.supportedValuesOf('timeZone');
const specialTimeZones = timeZones.filter(tz => !tz.includes('/'));
console.log(specialTimeZones);
// 출력: ["UTC"]
UTC 식별자는 오프셋이 없고 일광 절약 시간 변경이 없는 협정 세계시를 나타냅니다. 이 식별자는 로컬 시간대가 아닌 보편적인 참조 프레임으로 시간을 표시하고자 할 때 유용합니다.
일부 환경에서는 GMT나 Etc/GMT+5와 같은 영역 오프셋과 같은 추가 특수 식별자를 포함합니다. 애플리케이션에 표준 지리적 시간대만 필요한 경우 이러한 항목을 필터링할 수 있습니다:
function getGeographicTimeZones() {
const timeZones = Intl.supportedValuesOf('timeZone');
return timeZones.filter(timeZone => {
return timeZone.includes('/') && !timeZone.startsWith('Etc/');
});
}
const geographicTimeZones = getGeographicTimeZones();
console.log(geographicTimeZones.length);
// 출력: 400개 이상
이렇게 하면 비지리적 식별자를 필터링하고 표준 도시 기반 시간대만 남게 됩니다.
시간대 별칭 이해하기
IANA 데이터베이스에는 동일한 시간대 규칙을 참조하는 여러 식별자가 포함되어 있습니다. 예를 들어, Asia/Calcutta와 Asia/Kolkata는 모두 인도 표준시를 나타내지만, Kolkata가 현대적인 이름입니다.
Intl.supportedValuesOf() 메서드는 정식 식별자를 반환합니다. 사용자가 별칭을 제공하더라도 Intl.DateTimeFormat에서는 여전히 작동합니다:
const canonicalFormatter = new Intl.DateTimeFormat('en-US', {
timeZone: 'Asia/Kolkata',
timeZoneName: 'long'
});
const aliasFormatter = new Intl.DateTimeFormat('en-US', {
timeZone: 'Asia/Calcutta',
timeZoneName: 'long'
});
const date = new Date('2025-10-15T12:00:00Z');
console.log(canonicalFormatter.format(date));
// 출력: 인도 표준시 기준 시간
console.log(aliasFormatter.format(date));
// 출력: 인도 표준시 기준 시간
별칭이 내부적으로 정식 식별자에 매핑되기 때문에 두 포맷터 모두 동일한 결과를 생성합니다.
그러나 지원되는 값 목록에는 정식 식별자만 포함됩니다. 사용자 입력을 검증하는 경우 별칭을 정식 형식으로 정규화하는 것을 고려하세요:
function normalizeTimeZone(timeZone) {
try {
const formatter = new Intl.DateTimeFormat('en-US', { timeZone });
return formatter.resolvedOptions().timeZone;
} catch (error) {
return null;
}
}
console.log(normalizeTimeZone('Asia/Calcutta'));
// 출력: "Asia/Kolkata"
console.log(normalizeTimeZone('America/New_York'));
// 출력: "America/New_York"
console.log(normalizeTimeZone('Invalid/Zone'));
// 출력: null
이 함수는 제공된 시간대로 포맷터를 생성하고 해결된 옵션에서 정식 식별자를 추출합니다. 식별자가 유효하지 않으면 포맷터는 오류를 발생시키고 함수는 null을 반환합니다.
브라우저 지원 및 호환성
Intl.supportedValuesOf() 메서드는 최신 브라우저 및 Node.js 버전에서 사용할 수 있습니다:
- Chrome 99 이상
- Firefox 93 이상
- Safari 15.4 이상
- Edge 99 이상
- Node.js 18.0.0 이상
이전 환경의 경우, 메서드를 기능 감지하고 대체 방안을 제공할 수 있습니다:
function getSupportedTimeZones() {
if (typeof Intl.supportedValuesOf === 'function') {
return Intl.supportedValuesOf('timeZone');
}
return [
'Africa/Cairo',
'America/New_York',
'America/Chicago',
'America/Denver',
'America/Los_Angeles',
'Asia/Dubai',
'Asia/Kolkata',
'Asia/Tokyo',
'Australia/Sydney',
'Europe/London',
'Europe/Paris',
'Pacific/Auckland',
'UTC'
];
}
const timeZones = getSupportedTimeZones();
이 함수는 Intl.supportedValuesOf가 존재하는지 확인하고 사용 가능한 경우 전체 목록을 반환합니다. 그렇지 않으면 일반적인 시간대의 더 작은 하드코딩된 목록을 반환합니다. 이 대체 방안은 이전 환경에서도 애플리케이션이 작동하도록 보장하면서 최신 환경에서는 전체 목록을 제공합니다.