JavaScriptでイベントをカウントダウン!Temporalを使ってタイマーを作ってみました

こんにちは、さるまりんです🐒

イベントが近づくと、カウントダウンしたくなりませんか?夏休みが始まる。好きなアーティストのコンサートがある。夏はイベントが多いですよね。
今回は、JavaScriptの日付API「Temporalを使って、複数イベントに対応したカウントダウンタイマーを作ってみます。

特別なフレームワークは不要です!Plain JavaScript + HTMLだけで動くシンプルな構成でやってみました。

しかも!

  • イベント当日は特別な表示
  • イベントが過ぎたら自動で次のカウント対象に切り替え

と、ちょっと色々組み込んであります。

対象イベント

対象イベントはこんな風に配列で複数定義できます。

const events = [
  {
    title: "バナナの日",
    date: Temporal.PlainDateTime.from({ year: 2025, month: 8, day: 7, hour: 8, minute: 7 })
  },
  {
    title: "洋菓子の日",
    date: Temporal.PlainDateTime.from({ year: 2025, month: 9, day: 29, hour: 0, minute: 0 })
  },
  {
    title: "テディーベアズ・デー",
    date: Temporal.PlainDateTime.from({ year: 2025, month: 10, day: 27, hour: 0, minute: 0 })
  }
];

Temporal.PlainDateTimeでイベント日時を定義。
当日になったら"T🎉 今日は <strong>${event.title}</strong> です!"と表示され、日が変わると次のイベントにスイッチします!

HTMLとJSのコードです

ブラウザが対応していたら貼るだけで動く想定です。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8" />
  <title>カウントダウン</title>
  <style>
    body { font-family: sans-serif; text-align: center; padding: 2em; }
    h1 { font-size: 2em; }
    .countdown { font-size: 1.5em; margin-top: 1em; }
  </style>
  <script type="module">
    import { Temporal } from 'https://esm.sh/@js-temporal/polyfill';

    const events = [
      {
        title: "バナナの日",
        date: Temporal.PlainDateTime.from({ year: 2025, month: 8, day: 7, hour: 8, minute: 7 })
      },
      {
        title: "洋菓子の日",
        date: Temporal.PlainDateTime.from({ year: 2025, month: 9, day: 29, hour: 0, minute: 0 })
      },
      {
        title: "テディーベアズ・デー",
        date: Temporal.PlainDateTime.from({ year: 2025, month: 10, day: 27, hour: 0, minute: 0 })
      }
    ];

    function findNextEvent(now) {
      for (const e of events) {
        const eventStart = e.date;
        const eventEnd = eventStart.add({ hours: 24 });

        if (Temporal.PlainDateTime.compare(now, eventStart) < 0) {
          return e; // まだこれから
        }

        if (
          Temporal.PlainDateTime.compare(now, eventStart) >= 0 &&
          Temporal.PlainDateTime.compare(now, eventEnd) < 0
        ) {
          return { ...e, today: true }; // 当日
        }
      }

      return null; // 全て終了
    }

    function updateCountdown() {
      const now = Temporal.Now.plainDateTimeISO();
      const event = findNextEvent(now);
      const container = document.getElementById('countdown');

      if (!event) {
        container.innerHTML = '📅 すべてのイベントが終了しました';
        return;
      }

      if (event.today) {
        container.innerHTML = `🎉 今日は <strong>${event.title}</strong> です!`;
        return;
      }

      const diff = event.date.since(now, {
        largestUnit: "days",
        smallestUnit: "seconds"
      });

      container.innerHTML = `🕒 次のイベント:<strong>${event.title}</strong><br />`
        + `残り:${diff.days}日 ${diff.hours}時間 ${diff.minutes}分 ${Math.floor(diff.seconds)}秒`;
    }

    updateCountdown(); // 初回即時表示
    setInterval(updateCountdown, 1000); // 毎秒更新
  </script>
</head>
<body>
  <h1>イベントまでのカウントダウン</h1>
  <div id="countdown" class="countdown"></div>
</body>
</html>

このコードをそのままHTMLファイルとして保存すれば、即カウントダウン画面として使えます。
見た目は色々やってみる必要がありますね。(得意な分野じゃないのでフロント技術も頑張ります。)

Temporalって?

で、ここまで使ってきましたがTemporal使うのは初めてでした。これはDateよりも直感的に使えそうな新しい日付APIで、現時点(2025年7月)でも情報を見る限り“Experimental”とあるので、まだ実験的なもののようです。(詳しくはこちら → https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal)
このAPIで時間帯やカレンダー、演算も安全に扱えるようになり、Temporal.Now.plainDateTimeISO()date.since()など、分かりやすそうな関数が多いです。また@js-temporal/polyfillを使えばどの環境でも試せます。

推しの誕生日、ライブ、記念日、スケジュールアプリやイベントサイト、チーム内の締切リマインド。
いろんなことに応用できそうですよね。

またひとつ、楽しくなる技術に触れることができました。まだまだ見始めなのでもっといろんな使い方を覚えていきたいです。次は、通知やアラームの追加もしてみたいと思っています。

読んでくださってありがとうございました。

それではまた!