ユーザーのロケールに合わせた時刻のフォーマット方法

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の表示方法も異なります。英語ではAMPMを使用し、スペイン語ではa.m.p.m.を使用し、一部のロケールではこれらの表示を時刻の後ではなく前に配置します。

時刻を表示する際には、時間形式と特定のフォーマット規則の両方においてユーザーの期待に合わせる必要があります。

Intl.DateTimeFormat を使用して時刻をフォーマットする

Intl.DateTimeFormat コンストラクタは、ロケール固有の規則を適用するフォーマッタを作成します。時刻をフォーマットするには、最初の引数としてロケール識別子を渡し、2番目の引数で時刻関連のオプションを指定します。

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));
// 出力: "3:30 PM"

これにより、時間と分を表示する米国英語用のフォーマッタが作成されます。hourminuteオプションは、フォーマッタにこれらのコンポーネントを含めるよう指示します。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));
// 出力: "3:30 PM"

const gbFormatter = new Intl.DateTimeFormat('en-GB', {
  hour: 'numeric',
  minute: 'numeric'
});
console.log(gbFormatter.format(date));
// 出力: "15:30"

const deFormatter = new Intl.DateTimeFormat('de-DE', {
  hour: 'numeric',
  minute: 'numeric'
});
console.log(deFormatter.format(date));
// 出力: "15:30"

const frFormatter = new Intl.DateTimeFormat('fr-FR', {
  hour: 'numeric',
  minute: 'numeric'
});
console.log(frFormatter.format(date));
// 出力: "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));
// 出力: "3:30:45 PM"

secondオプションはhourminuteと同じように機能します。出力に秒を含めるには、'numeric'に設定します。

2桁表示による桁数の制御

hourminutesecondオプションは2つの値を受け付けます:'numeric''2-digit'です。'numeric'値はパディングなしで桁を表示し、'2-digit'は常に先頭にゼロを付けて2桁で表示します。

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));
// 出力: "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));
// 出力: "09:05:03 AM"

numericフォーマッタは時間を1桁で表示し、9:05:03 AMと表示します。2桁フォーマッタは時間の先頭にゼロを付けて09:05:03 AMと表示します。分と秒は設定に関わらず、通常はパディングされるため、どちらも2桁で表示されます。

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));
// 出力: "3:30 pm"

const hour24Formatter = new Intl.DateTimeFormat('en-US', {
  hour: 'numeric',
  minute: 'numeric',
  hour12: false
});
console.log(hour24Formatter.format(date));
// 出力: "15:30"

hour12: trueを設定すると、通常24時間形式を使用するロケールでも12時間形式が強制されます。hour12: falseを設定すると、通常12時間形式を使用するロケールでも24時間形式が強制されます。

ロケールは句読点やスペースなどの他のフォーマット詳細を決定します。hour12: trueを設定した英国フォーマッタは小文字のpm3:30 pmと表示しますが、米国フォーマッタは大文字のPM3: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));
// 出力はユーザーのロケールによって異なります
// en-USの場合: "3:30 PM"
// en-GBの場合: "15:30"
// de-DEの場合: "15:30"
// 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));
// 出力: "9:00 AM"

console.log(formatter.format(time2));
// 出力: "3:30 PM"

console.log(formatter.format(time3));
// 出力: "11:45 PM"

ISO 8601日時文字列はYYYY-MM-DDTHH:MM:SS形式を使用します。Tは日付と時刻を区切ります。この形式は明確で、すべてのロケールとタイムゾーンで一貫して機能します。

タイムスタンプから時刻をフォーマットする

UnixタイムスタンプからDateオブジェクトを作成することもできます。Unixタイムスタンプは1970年1月1日UTC以降のミリ秒数を表します。

const timestamp = 1710515400000; // 2025年3月15日 午後3時30分
const date = new Date(timestamp);

const formatter = new Intl.DateTimeFormat('en-US', {
  hour: 'numeric',
  minute: 'numeric'
});
console.log(formatter.format(date));
// 出力: "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));
// 出力: "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));
// 出力: "3:45:12 PM"(実行時の現在時刻)

現在のタイムスタンプを数値として返すDate.now()を直接渡すこともできます。

const formatter = new Intl.DateTimeFormat('en-US', {
  hour: 'numeric',
  minute: 'numeric',
  second: 'numeric'
});

console.log(formatter.format(Date.now()));
// 出力: "3:45:12 PM"(実行時の現在時刻)

両方のアプローチは同じ結果を生成します。

パフォーマンスのためにフォーマッターを再利用する

新しい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));
});
// 出力:
// "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);

フォーマットされた文字列は他の文字列値と同様に機能します。テキストコンテンツ、属性、またはユーザーに情報を表示するその他のコンテキストに挿入することができます。