時間を2:30:45の形式でフォーマットする方法

デジタル時計形式でコロン区切りの時間を表示する

はじめに

動画プレーヤー、ストップウォッチ、カウントダウンタイマーは、見慣れた形式で時間を表示します。「2:30:45」を見れば、2時間30分45秒を意味することがすぐに理解できます。このデジタル時計形式では、ラベルやスペースを使わずにコロンで時間単位を区切ります。

この形式を手動で構築するには、数値をゼロでパディングし、異なる時間の長さを処理する必要があります。5分30秒の動画は「5:30」と表示され、2時間の動画は「2:00:00」と表示されます。エッジケースを含めるとロジックが複雑になります。

function formatDuration(seconds) {
  const h = Math.floor(seconds / 3600);
  const m = Math.floor((seconds % 3600) / 60);
  const s = Math.floor(seconds % 60);

  if (h > 0) {
    return `${h}:${String(m).padStart(2, '0')}:${String(s).padStart(2, '0')}`;
  }
  return `${m}:${String(s).padStart(2, '0')}`;
}

Intl.DurationFormat APIは、digital スタイルオプションを使用して、これを自動的に処理します。任意の時間の長さに対して正しい形式を生成します。

const duration = { hours: 2, minutes: 30, seconds: 45 };
new Intl.DurationFormat('en', { style: 'digital' }).format(duration);
// "2:30:45"

タイマー表示にはdigitalスタイルを使用する

digital スタイルは、デジタル時計のように時間をフォーマットします。フォーマッターを作成する際に、style オプションを "digital" に設定します。

const formatter = new Intl.DurationFormat('en', { style: 'digital' });

表示したい時間単位を含む期間オブジェクトを渡します。フォーマッターは単位間にコロンを追加し、必要に応じて値をゼロでパディングします。

const duration = { hours: 1, minutes: 5, seconds: 30 };
formatter.format(duration);
// "1:05:30"

分が「5」ではなく「05」と表示されることに注目してください。フォーマッターは、時間が存在する場合、自動的に分を2桁にパディングします。これにより、リストやテーブルでの配置が維持されます。

時間を含まない期間の場合は、期間オブジェクトからそのプロパティを省略します。

const shortDuration = { minutes: 5, seconds: 30 };
formatter.format(shortDuration);
// "5:30"

分が最大の単位である場合、パディングは不要になります。形式は明確さを保ちながらコンパクトなままです。

デジタル形式が異なる長さの時間をどのように処理するか

デジタル形式は、期間オブジェクトに含める単位に基づいて出力を調整します。これは、ビデオプレーヤーがビデオの長さに応じて表示を調整する方法と一致します。

短い時間は分と秒のみを表示します。

const formatter = new Intl.DurationFormat('en', { style: 'digital' });

const short = { minutes: 3, seconds: 42 };
formatter.format(short);
// "3:42"

長い時間には時間が含まれます。

const long = { hours: 2, minutes: 15, seconds: 8 };
formatter.format(long);
// "2:15:08"

時間が表示される場合、すべての小さい単位は2桁にパディングされます。時間がない場合、分はパディングなしで表示されますが、秒は引き続きパディングされます。

このパディングルールにより、スペースを無駄にすることなく一貫した配置が作成されます。短いビデオのリストでは「5:30」、「12:45」、「8:02」のようにコロンが揃って表示されます。長いビデオのリストでは「1:05:30」、「2:12:45」、「3:08:02」のように一貫した形式で表示されます。

インターフェースに必要な単位のみを含めてください。1時間を超えないカウントダウンタイマーは、時間を完全に省略できます。

const countdown = { minutes: 42, seconds: 15 };
formatter.format(countdown);
// "42:15"

ゼロパディングと表示オプションの制御

デジタル形式はデフォルトのパディングルールを使用しますが、個々の時間単位のオプションを指定することでそれらを上書きできます。

各単位の表示方法を制御するには、単位固有のオプションを設定します。numeric値は、パディングなしで数値を表示します。2-digit値は、2桁のパディングを強制します。

const duration = { hours: 1, minutes: 5, seconds: 3 };

new Intl.DurationFormat('en', {
  style: 'digital',
  hours: 'numeric',
  minutes: '2-digit',
  seconds: '2-digit'
}).format(duration);
// "1:05:03"

これはデフォルトの動作です。異なる形式が必要な場合にのみ、これらのオプションを指定する必要があります。

時間を常に2桁で表示するように強制します。

new Intl.DurationFormat('en', {
  style: 'digital',
  hours: '2-digit',
  minutes: '2-digit',
  seconds: '2-digit'
}).format(duration);
// "01:05:03"

この形式は、一貫した幅によってレイアウトのずれを防ぐ同期表示に適しています。

よりコンパクトな表示のために秒からパディングを削除します。

const shortDuration = { minutes: 5, seconds: 3 };

new Intl.DurationFormat('en', {
  style: 'digital',
  seconds: 'numeric'
}).format(shortDuration);
// "5:3"

この形式はあまり一般的ではありません。ユーザーはデジタル表示で秒がパディングされることを期待しているためです。

デジタル形式に小数秒を追加する

一部のアプリケーションでは、ミリ秒やマイクロ秒を表示する必要があります。デジタル形式はfractionalDigitsオプションで小数秒をサポートしています。

秒の後に表示する小数点以下の桁数を設定します。

const duration = {
  minutes: 5,
  seconds: 30,
  milliseconds: 123
};

new Intl.DurationFormat('en', {
  style: 'digital',
  fractionalDigits: 3
}).format(duration);
// "5:30.123"

フォーマッターは秒の後に小数点を追加し、指定された桁数の小数部分を表示します。

ストップウォッチは通常、100分の1秒を表示します。

const lap = {
  minutes: 1,
  seconds: 23,
  milliseconds: 450
};

new Intl.DurationFormat('en', {
  style: 'digital',
  fractionalDigits: 2
}).format(lap);
// "1:23.45"

フォーマッターは指定された精度に丸めます。450ミリ秒の値は45/100秒になります。

マイクロ秒の精度が必要な場合は、durationオブジェクトにマイクロ秒を含め、より高い小数桁数を設定します。

const precise = {
  seconds: 42,
  milliseconds: 123,
  microseconds: 456
};

new Intl.DurationFormat('en', {
  style: 'digital',
  fractionalDigits: 6
}).format(precise);
// "42.123456"

デジタル形式と他のスタイルを使い分けるタイミング

インターフェースがタイマー、ストップウォッチ、またはメディアプレーヤーに似ている場合は、デジタル形式を選択してください。ユーザーはこれらのコンテキストでこの形式を期待しています。

ビデオプレーヤーのコントロールにはデジタル形式を使用します。

function formatVideoTime(seconds) {
  const hours = Math.floor(seconds / 3600);
  const minutes = Math.floor((seconds % 3600) / 60);
  const secs = Math.floor(seconds % 60);

  const duration = hours > 0
    ? { hours, minutes, seconds: secs }
    : { minutes, seconds: secs };

  return new Intl.DurationFormat('en', { style: 'digital' }).format(duration);
}

formatVideoTime(6345); // "1:45:45"
formatVideoTime(125);  // "2:05"

カウントダウンタイマーやストップウォッチにはデジタル形式を使用します。

function formatStopwatch(milliseconds) {
  const minutes = Math.floor(milliseconds / 60000);
  const seconds = Math.floor((milliseconds % 60000) / 1000);
  const ms = milliseconds % 1000;

  return new Intl.DurationFormat('en', {
    style: 'digital',
    fractionalDigits: 2
  }).format({ minutes, seconds, milliseconds: ms });
}

formatStopwatch(125450); // "2:05.45"

文章内で期間を表示する場合や、ラベルが明確性を向上させる場合は、他のスタイルを使用します。フライト予約サイトでは、コンテキストがタイマーではないため、「8:15:00」ではなく「8時間15分」と表示します。

// Good for prose and descriptions
new Intl.DurationFormat('en', { style: 'short' }).format(duration);
// "1 hr, 46 min and 40 sec"

// Good for timer displays
new Intl.DurationFormat('en', { style: 'digital' }).format(duration);
// "1:46:40"

古いブラウザ向けにデジタル形式を手動で構築する

Intl.DurationFormat APIは2025年3月に利用可能になりました。古いブラウザの場合は、デジタル形式を手動で構築します。

手動アプローチでは、合計秒数から時間単位を計算し、値をゼロでパディングする必要があります。

function formatDigitalDuration(totalSeconds) {
  const hours = Math.floor(totalSeconds / 3600);
  const minutes = Math.floor((totalSeconds % 3600) / 60);
  const seconds = Math.floor(totalSeconds % 60);

  if (hours > 0) {
    const paddedMinutes = String(minutes).padStart(2, '0');
    const paddedSeconds = String(seconds).padStart(2, '0');
    return `${hours}:${paddedMinutes}:${paddedSeconds}`;
  } else {
    const paddedSeconds = String(seconds).padStart(2, '0');
    return `${minutes}:${paddedSeconds}`;
  }
}

formatDigitalDuration(6345); // "1:45:45"
formatDigitalDuration(125);  // "2:05"

この関数は合計秒数を3600で割って時間を取得します。余りを60で割ると分が得られます。最終的な余りが秒です。

padStart()メソッドは、値が10未満の場合に先頭にゼロを追加します。これにより、「5」が「05」になり、一貫したフォーマットが保証されます。

合計秒数ではなく期間オブジェクトとして保存された期間の場合は、値を直接抽出します。

function formatDurationObject(duration) {
  const h = duration.hours || 0;
  const m = duration.minutes || 0;
  const s = duration.seconds || 0;

  if (h > 0) {
    return `${h}:${String(m).padStart(2, '0')}:${String(s).padStart(2, '0')}`;
  }
  return `${m}:${String(s).padStart(2, '0')}`;
}

formatDurationObject({ hours: 1, minutes: 5, seconds: 30 }); // "1:05:30"
formatDurationObject({ minutes: 5, seconds: 30 }); // "5:30"

ミリ秒を含めて小数点精度でフォーマットすることで、小数秒を追加します。

function formatWithMilliseconds(duration) {
  const m = duration.minutes || 0;
  const s = duration.seconds || 0;
  const ms = duration.milliseconds || 0;

  const paddedSeconds = String(s).padStart(2, '0');
  const fractional = String(ms).padStart(3, '0').slice(0, 2);

  return `${m}:${paddedSeconds}.${fractional}`;
}

formatWithMilliseconds({ minutes: 1, seconds: 23, milliseconds: 450 });
// "1:23.45"

使用する前にAPIサポートを確認してください。

function formatDuration(duration) {
  if (typeof Intl.DurationFormat !== 'undefined') {
    return new Intl.DurationFormat('en', { style: 'digital' }).format(duration);
  } else {
    return formatDurationObject(duration);
  }
}

このアプローチは、ネイティブAPIが利用可能な場合はそれを使用しながら、すべてのブラウザで一貫した出力を提供します。

動画プレーヤーとタイマーの一般的なパターン

動画プレーヤーは、現在時刻と合計期間の両方をフォーマットする必要があります。両方の値を処理する再利用可能なフォーマッターを作成します。

const videoFormatter = new Intl.DurationFormat('en', { style: 'digital' });

function formatVideoPosition(currentSeconds, totalSeconds) {
  const current = secondsToDuration(currentSeconds);
  const total = secondsToDuration(totalSeconds);

  return `${videoFormatter.format(current)} / ${videoFormatter.format(total)}`;
}

function secondsToDuration(seconds) {
  const hours = Math.floor(seconds / 3600);
  const minutes = Math.floor((seconds % 3600) / 60);
  const secs = Math.floor(seconds % 60);

  return hours > 0
    ? { hours, minutes, seconds: secs }
    : { minutes, seconds: secs };
}

formatVideoPosition(125, 6345); // "2:05 / 1:45:45"

フレームごとに更新されるカウントダウンタイマーの場合は、フォーマッターを一度作成して再利用します。

const timerFormatter = new Intl.DurationFormat('en', {
  style: 'digital',
  fractionalDigits: 2
});

function updateTimer(remainingMs) {
  const duration = {
    minutes: Math.floor(remainingMs / 60000),
    seconds: Math.floor((remainingMs % 60000) / 1000),
    milliseconds: remainingMs % 1000
  };

  document.getElementById('timer').textContent = timerFormatter.format(duration);
}

ラップタイムを表示するストップウォッチの場合は、経過時間を小数秒でフォーマットします。

const lapFormatter = new Intl.DurationFormat('en', {
  style: 'digital',
  fractionalDigits: 3
});

function formatLapTime(startMs, endMs) {
  const elapsedMs = endMs - startMs;

  return lapFormatter.format({
    minutes: Math.floor(elapsedMs / 60000),
    seconds: Math.floor((elapsedMs % 60000) / 1000),
    milliseconds: elapsedMs % 1000
  });
}

const lap1Start = performance.now();
// ... time passes ...
const lap1End = performance.now();

formatLapTime(lap1Start, lap1End); // "1:23.456"

これらのパターンは、クリーンで再利用可能なコードを維持しながら、最も一般的な期間フォーマットのシナリオを処理します。