有効なタイムゾーン識別子のリストを取得する方法

ドロップダウンの構築とユーザー入力の検証のために、JavaScriptでサポートされているすべてのIANAタイムゾーン識別子を取得する

はじめに

ユーザーがタイムゾーンを選択できる機能を構築する際、どのタイムゾーン識別子が有効かを把握する必要があります。ニューヨークのユーザーはAmerica/New_Yorkを選択する必要があるかもしれませんが、東京のユーザーはAsia/Tokyoを必要とします。タイムゾーンのリストをハードコーディングすると、いくつかの問題が発生します。

まず、リストが古くなります。政府が夏時間のルールを変更したり、新しいタイムゾーンを作成したりすると、タイムゾーンの定義が変わります。次に、異なるJavaScript環境は異なるタイムゾーンをサポートします。Chromeで動作するタイムゾーンが、古いブラウザやNode.jsのバージョンでは動作しない可能性があります。第三に、数百のタイムゾーン文字列を手動で管理すると、タイプミスや不整合の機会が生まれます。

JavaScriptは、現在の環境がサポートするすべてのタイムゾーン識別子を取得するためのIntl.supportedValuesOf()メソッドを提供します。これにより、アプリケーションは正しく動作するタイムゾーンのみを提供し、タイムゾーンデータベースの変更に対応し続けることができます。

タイムゾーン識別子とは

タイムゾーン識別子は、一貫した時間ルールを持つ地理的地域を表す標準化された文字列です。これらは、世界中のタイムゾーンと夏時間の変更を追跡する国際組織によって管理されている包括的なリストであるIANAタイムゾーンデータベースに由来します。

識別子は、異なるシステム間で明確かつ安定した特定の形式を使用します。この形式を理解することで、タイムゾーンを効果的に扱うことができます。

IANAタイムゾーン識別子の形式を理解する

IANAタイムゾーン識別子はArea/Locationのパターンに従います。ここで、エリアは大陸または海洋を表し、ロケーションはそのエリア内の都市または地域を表します。

const examples = [
  'America/New_York',
  'Europe/London',
  'Asia/Tokyo',
  'Australia/Sydney',
  'Pacific/Auckland'
];

エリアは以下に対応します:

  • Americaは北米および南米
  • Europeはヨーロッパの地域
  • Asiaはアジアの地域
  • Africaはアフリカの地域
  • Australiaはオーストラリアの地域
  • Pacificは太平洋の島々
  • Atlanticは大西洋の島々
  • Indianはインド洋の島々
  • Antarcticaは南極の研究基地

ロケーションは通常、そのタイムゾーンで最大または最も代表的な都市を表します。ニューヨークはアメリカ合衆国の東部タイムゾーンを表します。東京は日本を表します。シドニーはオーストラリアの東部タイムゾーンを表します。

一部の識別子には、より大きなエリア内の地域を表す3つの部分が含まれます:

const detailedExamples = [
  'America/Indiana/Indianapolis',
  'America/Kentucky/Louisville',
  'America/North_Dakota/Center'
];

これらの複数部分の識別子は、同じ国内で異なる時刻ルールに従う地域を区別します。

データベースは都市名のスペースの代わりにアンダースコアを使用します:

const underscoreExamples = [
  'America/New_York',    // Not "New York"
  'America/Los_Angeles', // Not "Los Angeles"
  'Asia/Ho_Chi_Minh'     // Not "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);
// Output: over 400

console.log(timeZones.slice(0, 10));
// Output: [
//   "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));
// Output: "October 15, 2025 at 12:00 PM"

このメソッドは、返すすべての識別子がIntl APIで正しく動作することを保証します。

タイムゾーンセレクターの構築

すべてのタイムゾーン識別子を取得する最も一般的なユースケースは、ユーザーがタイムゾーンを選択できるドロップダウンまたはselect要素を構築することです。

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);

これにより、サポートされているすべてのタイムゾーンのオプションを持つselect要素が作成されます。ユーザーはリストをスクロールして、自分の場所を選択できます。

ただし、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));
// Output: [
//   "Africa", "America", "Antarctica", "Arctic",
//   "Asia", "Atlantic", "Australia", "Europe",
//   "Indian", "Pacific", "Etc"
// ]

console.log(grouped['America'].slice(0, 5));
// Output: [
//   "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);

これにより、タイムゾーンが地域の見出しの下に表示されるselect要素が作成されます。オプションのテキストには識別子の都市部分のみが表示され、リストがより読みやすくなります。

地域別のタイムゾーンのフィルタリング

特定の地域のタイムゾーンのみが必要な場合があります。例えば、北米のユーザーのみにサービスを提供するアプリケーションでは、アメリカのタイムゾーンのみを表示する場合があります。

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'));
// Output: true

console.log(isValidTimeZone('Europe/London'));
// Output: true

console.log(isValidTimeZone('Invalid/TimeZone'));
// Output: false

console.log(isValidTimeZone('EST'));
// Output: false

この関数は、指定された文字列がサポートされているタイムゾーンのリストに含まれているかどうかを確認します。識別子が無効な場合は、それを拒否するか、ユーザーに有効なオプションから選択するよう促すことができます。

識別子を使用してエラーをキャッチすることもできます。

function validateTimeZoneByCatch(timeZone) {
  try {
    new Intl.DateTimeFormat('en-US', { timeZone });
    return true;
  } catch (error) {
    return false;
  }
}

console.log(validateTimeZoneByCatch('America/New_York'));
// Output: true

console.log(validateTimeZoneByCatch('Invalid/TimeZone'));
// Output: 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}`);
});

// Output:
// 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');
// In January: GMT-5

const newYorkSummer = getTimeZoneOffset('America/New_York');
// In July: 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);
// Output: "America/New_York" (or user's actual time zone)

これはユーザーのシステムタイムゾーンの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);
// Output: ["UTC"]

UTC識別子は協定世界時を表し、オフセットや夏時間の変更がありません。この識別子は、ローカルタイムゾーンではなく普遍的な基準枠で時刻を表示したい場合に便利です。

一部の環境には、GMTEtc/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);
// Output: over 400

これにより、非地理的識別子がフィルタリングされ、標準的な都市ベースのタイムゾーンのみが残ります。

タイムゾーンエイリアスの理解

IANAデータベースには、同じタイムゾーンルールを参照する複数の識別子が含まれています。たとえば、Asia/CalcuttaAsia/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));
// Output: time in Indian Standard Time

console.log(aliasFormatter.format(date));
// Output: time in Indian Standard Time

両方のフォーマッターは同じ結果を生成します。これは、エイリアスが内部的に正規識別子にマッピングされるためです。

ただし、サポートされている値のリストには正規識別子のみが含まれます。ユーザー入力を検証する場合は、エイリアスを正規形式に正規化することを検討してください。

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'));
// Output: "Asia/Kolkata"

console.log(normalizeTimeZone('America/New_York'));
// Output: "America/New_York"

console.log(normalizeTimeZone('Invalid/Zone'));
// Output: 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が存在するかどうかを確認し、利用可能な場合は完全なリストを返します。利用できない場合は、一般的なタイムゾーンの小さなハードコードされたリストを返します。フォールバックにより、古い環境でもアプリケーションが動作し、最新の環境では完全なリストが提供されます。