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

ドロップダウンの構築やユーザー入力の検証のために、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',    // 「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);
// 出力: 150以上

console.log(americanTimeZones.slice(0, 5));
// 出力: [
//   "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);
// 出力: 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);
// 出力: ["America/New_York"]

const londonResults = searchTimeZones('london');
console.log(londonResults);
// 出力: ["Europe/London"]

const tokyoResults = searchTimeZones('tokyo');
console.log(tokyoResults);
// 出力: ["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);
// 出力: ["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識別子は協定世界時を表し、オフセットもなく夏時間の変更もありません。この識別子は、ローカルタイムゾーンではなく普遍的な基準枠で時間を表示したい場合に便利です。

一部の環境では、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);
// 出力: 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));
// 出力: インド標準時の時間

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