【JavaScript】特定日時までのカウントダウンタイマーの作り方

## はじめに
みなさんは、特定日時までのカウントダウンタイマーを作ったことがありますか？

イベントの特設ページなどでは、よく開催日までのカウントダウンタイマーをみます。
この記事では、そんなカウントダウンタイマーを作ったので紹介しようと思います。

## 完成系
ゴールの日時を入力すると、ゴールの日時までカウントダウンが始まります。
ゴールに日時が過ぎると `残り0日0時間0分0秒` となります。

この記事では、この特定日時までのカウントダウンタイマーの作り方を紹介します。

<p class="codepen" data-height="500" data-default-tab="result" data-slug-hash="NWJOqaJ" data-user="sp_degu" style="height: 500px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/sp_degu/pen/NWJOqaJ">
  Timer</a> by でぐぅー | Qiita (<a href="https://codepen.io/sp_degu">@sp_degu</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

## 作り方
### 01. HTMLを記載する
HTMLは以下のように記載します。
`<input>` は、入力した値をJavaScriptで使うため、`id="datetime"` を指定しています。
また同様に、JavaScriptで残り時間の数値を反映させるため、日・時間・分・秒の値にもidを指定しています。

```sample.html
<div class="input-wrapper">
  <label>ゴール</label>
  <input type="datetime-local" id="datetime"/>
</div>
<div class="countdown-wrapper">
  <span>残り</span>
  <span id="day" class="time"></span>
  <span class="unit">日</span>
  <span id="hour" class="time"></span>
  <span class="unit">時間</span>
  <span id="minute" class="time"></span>
  <span class="unit">分</span>
  <span id="second" class="time"></span>
  <span class="unit">秒</span>
<div>
```

### 02. CSSを記載する
CSSは以下のように記載します。
このカウントダウンタイマーでは、スタイルは関係ないので、任意のスタイルを記載ください。

```sample.css
body {
  align-content: center;
  background-color: #212529;
  color: white;
  display: grid;
  gap: 42px;
  height: calc(100vh - 40px);
  justify-items: center;
  margin: 0;
  padding: 20px 0;
  width: 100vw;
  color-scheme: dark;
}

.input-wrapper {
  background-color: rgb(128 128 128 / .2);
  border: 1px solid rgb(255 255 255 / .4);
  border-radius: 24px;
  display: grid;
  gap: 4px;
  padding: 16px;
}

input[type="datetime-local"] {
  border: none;
  border-radius: 8px;
  background: linear-gradient(0deg, rgba(0, 0, 0, .1) 0%, rgba(0, 0, 0, 0.10) 100%), rgba(0, 0, 0, .5);
  font-size: 16px;
  padding: 8px 12px;
}

.countdown-wrapper {
  align-items: flex-end;
  background-color: rgb(128 128 128 / .2);
  border: 1px solid rgb(255 255 255 / .4);
  border-radius: 24px;
  display: flex;
  padding: 12px 16px;
  
  & > .time {
    border-radius: 8px;
    background: linear-gradient(0deg, rgba(0, 0, 0, .1) 0%, rgba(0, 0, 0, 0.10) 100%), rgba(0, 0, 0, .5);
    font-size: 24px;
    font-weight: bold;
    line-height: 1;
    min-width: 48px;
    min-height: 48px;
    display: grid;
    place-items: center;
    padding: 4px;
    margin-left: 12px;
  }
  & > .unit {
    margin-left: 4px;
  }
}
```

### 03. JavaScriptを記載する
#### ⚪︎ カウントダウンする仕組み
1. 目標時刻(`datetime.value`)を取得する
    + その後、目標時間をユニックス時間[^1]に変換する （`unixEndDate`）
        + `Date.parse()` メソッドを使うことで、日時を表す文字列をユニックス時間[^1]に変換できる
1. 現時刻(`unixCurrentDate`)をユニックス時間[^1]で取得する
1. 目標時刻(`datetime.value`)と現時刻(`unixCurrentDate`)の差をUnixTimeで計算する （`leftDate`）
1. 目標時刻と現時刻の差から残り時間の日・時間・分・秒をそれぞれ表す
1. 日・時間・分・秒それぞれの値を表示させる
    + 目標時刻(`datetime.value`)と現時刻(`unixCurrentDate`)の差がマイナスになると、目標時刻を過ぎていることになるので、`残り0日0時間０分０秒`が表示されるようにする

この 1~5の手順を1秒ごとに実行させる

#### ⚪︎ 実装

```sample.js
const day = document.getElementById('day');
const hour = document.getElementById('hour');
const minute = document.getElementById('minute');
const second = document.getElementById('second');

function countDown(unixEndDate) {
  // 現時刻をUnixTimeで取得
  const unixCurrentDate = Date.parse(new Date().toISOString());
  // 目標時刻と現時刻の差をUnixTimeで計算
  let leftDate = unixEndDate - unixCurrentDate;
  // 目標時刻と現時刻の差から残り時間を計算
  let leftDayDate = Math.floor(leftDate / (1000 * 60 * 60 * 24));
  let leftHourDate = Math.floor((leftDate % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
  let leftMinuteDate = Math.floor((leftDate % (1000 * 60 * 60)) / (1000 * 60));
  let leftSecondDate = Math.floor((leftDate % (1000 * 60)) / 1000);
  // 残り時間を表示させる
  if (leftDate < 0){
    day.innerHTML = "0";
    hour.innerHTML = "0";
    minute.innerHTML = "0";
    second.innerHTML = "0";
  } else {
    day.innerHTML = `${leftDayDate}`;
    hour.innerHTML = `${leftHourDate}`;
    minute.innerHTML = `${leftMinuteDate}`;
    second.innerHTML = `${leftSecondDate}`;
  }
}

const datetime = document.getElementById('datetime');

window.addEventListener('DOMContentLoaded', function(){
  setInterval(() => {
    let unixEndDate = datetime.value ? Date.parse(datetime.value) : null;
    countDown(unixEndDate)
  }, 1000)
});
```

[^1]:[ユニックス時間](https://ja.wikipedia.org/wiki/UNIX%E6%99%82%E9%96%93)
UTC（協定世界時）での1970年1月1日午前0時0分0秒から何秒経過しているかを表している

## まとめ
この記事では、特定日時までのカウントダウンタイマーの作り方に付いて紹介しました。

もし、イベントの特設サイト等でカウントダウンタイマーを作る際は、ぜひ参考にしてみてください。

---

最後まで読んでくださってありがとうございます！

普段はデザインやフロントエンドを中心にQiitaに記事を投稿しているので、ぜひQiitaのフォローとX(Twitter)のフォローをお願いします。

https://twitter.com/degudegu2510