JavaScript勉強会

JavaScriptの学習日記

5.1 カウントダウンタイマー 《時間の計算とタイマー》 【JavaScript超入門】

JavaScriptの学習メモ。

今日は『確かな力が身につくJavaScript「超」入門』の第5章を読んでみます。

 

jsstudy.hatenablog.com

 

 

5.1 時間の計算とタイマー

(p.186)

4-2節で紹介したDateオブジェクトを使って、イベント告知サイトのトップページにあるような、カウントダウンタイマーを作りましょう。

当日の残り時間を計算してHTMLに表示します。

また、応用編ではもっと先の時間を設定して、そこまでの残り時間を表示してみます。

重要なポイントは2つ。

1つは未来の時刻から現在時刻を引き算する日時の計算

もう1つは、1秒後にまた同じ計算をして、HTMLに再表示する方法です。

時間をおいて同じ処理を繰り返すために、JavaScriptのタイマー機能を利用します。

 

Dateオブジェクトの日時を設定する方法

時刻Aから時刻Bまでの差を計算してみます。

→ 未来の時刻から現在の時刻を引いて、残り時間を計算する。

 

サンプルコード

<!doctype html>
<html>
<head>
    <meta charset="UTF-8">
    <title>5-01_countdown</title>
</head>
<body>
    <header>
        <h1>カウントダウンタイマー</h1>
        <h2>残り時間を計算するファンクションを作る</h2>
        <p>いまから<span id="timer"></span>以内に注文すると50%オフ!</p>
        <script>
            var countdown = function (due) {
                var now = new Date();

                var rest = due.getTime() - now.getTime();
                var sec = Math.floor(rest / 1000 % 60);
                var min = Math.floor(rest / 1000 / 60) % 60;
                var hours = Math.floor(rest / 1000 / 60 / 60) % 24;
                var days = Math.floor(rest / 1000 / 60 / 60 / 24);
                var count = [days, hours, min, sec];

                return count;
            }

            var goal = new Date();
            goal.setHours(23);
            goal.setMinutes(59);
            goal.setSeconds(59);

            console.log(countdown(goal));
            var counter = countdown(goal);
            var time = counter[1] + '時間' + counter[2] + '分' + counter[3] + '秒';
            document.getElementById('timer').textContent = time;

        </script>
</body>
</html>

 

実行結果

上記ファイルをブラウザーで開くと、以下のように表示されました。

 

f:id:jsstudy:20170510144919p:plain

 

コンソール画面には、以下のように表示されていました。

 

f:id:jsstudy:20170510145011p:plain

 

関数の返り値の中身は、数値が4個ある配列になっていました。

 

Dateオブジェクトに現在の日時を設定する方法

JavaScriptで日時のデータを扱うには、あらかじめJavaScriptで用意されているDateオブジェクトを利用します。

Dateオブジェクトをそのまま初期化したら、自動的に現在の日時が設定されます。

 

jsstudy.hatenablog.com

 

var now = new Date();

 

Dateオブジェクトに未来・過去の日時を設定する方法

Dateオブジェクトに未来や過去の日時を設定する方法は、いくつかあります。

 

  1. Dateオブジェクトの専用メソッドを使って日時を設定する
  2. Dateオブジェクトを初期化するときに日時を設定する

 

それぞれ見ていきましょう。

 

Dateオブジェクトの専用メソッドを使って日時を設定する

(P.190)

 

developer.mozilla.org

 

Date.prototype メソッド

セッター

Date.prototype.setFullYear()
地方時に基づき、指定された日時の「年」を完全な形で設定します。

Date.prototype.setMonth()
地方時に基づき、指定された日時の「月」を設定します。

Date.prototype.setDate()
地方時に基づき、指定された日時の「日」を設定します。

Date.prototype.setHours()
地方時に基づき、指定された日時の「時」を設定します。

Date.prototype.setMinutes()
地方時に基づき、指定された日時の「分」を設定します。

Date.prototype.setSeconds()
地方時に基づき、指定された日時の「秒」を設定します。

 

東京オリンピックの開催日時(2020年7月24日8時)は、以下のように設定できます。

var olympic = new Date();
olympic.setFullYear(2020);
olympic.setMonth(6);
olympic.setDate(24);
olympic.setHours(8);
olympic.setMinutes(0);
olympic.setSeconds(0);

Dateオブジェクトを初期化して、変数olympicに代入します。

(初期化した直後の時点では、olympicに現在の日時データが設定されています。)

 

Dateオブジェクトにあらかじめ用意されている専用のメソッド(セッター)を使って、年月日時分秒を別の値に変更することができます。

(Dateオブジェクトの「月」は、0から始まり11で終わる=7月は「6」になるので注意!)

 

Dateオブジェクトを初期化するときに日時を設定する

(P.199)

Dateオブジェクトのセッターで日時データを変更する以外に、Dateオブジェクトを初期化するときに日時を設定する方法もあります。

 

書式:日時を設定した状態でDateオブジェクトを初期化する
new Date(年, 月, 日, 時, 分, 秒, ミリ秒)

 

「new Date()」の()内にパラメーターを含めておくと、あらかじめ日時を設定した状態で初期化できるようになります。

パラメーターのうち「年」「月」は必須です。

それ以降はあってもなくてもよく、省略すれば「1日」「0時」「0分」「0秒」で初期化されます。

「月」は「実際の月 - 1」の数にする必要があるので注意しましょう。

 

東京オリンピックの開催日時(2020年7月24日8時)は、以下のように設定できます。

var olympic = new Date(2020, 6, 24, 8, 0, 0);

 

Dateオブジェクトのコンストラクタ関数に引き渡す引数の書式

developer.mozilla.org

 

標準ビルトインオブジェクト > Date

日付や時刻を扱うことが可能な、JavaScript の Date インスタンスを生成します。

Date オブジェクトは、1970 年 1 月 1 日 (UTC) から始まるミリ秒単位の時刻値を基準としています。

 

構文

new Date();

new Date(value);

new Date(dateString);

new Date(year, month[, day[, hour[, minutes[, seconds[, milliseconds]]]]]);

 

Dateオブジェクトを初期化するときに「dateString」=日時形式のデータを設定することもできます。

 

東京オリンピックの開催日時(2020年7月24日8時)は、以下のように設定できます。

var olympic = new Date("2020/07/24 08:00:00");

 

こちらの書き方だと、カレンダーと同じで「7月」は「07」と書けば良いので、人間には分かりやすいですね。

(月をマイナス1して、調整しなくてもOK)

 

UNIXタイムを利用した時間の計算

JavaScriptに限らず)日時を計算するときに、「ユニックスタイム」がよく利用されます。

 

UNIX時間 - Wikipedia

UNIX時間またはUNIX時刻(UNIX time(ユニックスタイム)、POSIX time(ポジックスタイム))とはコンピューターシステム上での時刻表現の一種。

UNIXエポック、すなわち協定世界時 (UTC) での1970年1月1日真夜中(午前0時0分0秒)の時刻からの形式的な経過秒数(すなわち、実質的な経過秒数から、その間に挿入された閏秒を引き、削除された閏秒を加えたもの)として表される。

 

システム内部では32ビットまたは64ビットの符号付整数 (signed int) で扱われていることが普通であり、特に32ビットで扱われている場合においては符号付整数が取れる最大値 2,147,483,647 を超える時点で時刻を扱えなくなるという問題がある。

これを2038年問題という。この時間を超えると負の位になり、誤作動が起こると言われている。

 

UNIXタイムは、1970年1月1日0時0分0秒からの経過時間を秒で表した数値です。

UNIXタイムは、別名「エポック秒」とも呼ばれてます。)

なので、UNIXタイムの単位は「秒」です。

 

未来の日時から現在の日時を引いて、残り時間を計算するには、

  1. 未来の日時をUNIXタイム(秒)に変換する
  2. 現在の日時をUNIXタイム(秒)に変換する
  3. 未来のUNIXタイム(秒)から現在のUNIXタイム(秒)を引く
  4. すると、残り時間が何秒か分かる
  5. 残り時間の秒を、人間が見やすいように、年月日時分秒などに変換する

という手順で計算できます。

 

getTime()メソッド

JavaScriptでDateオブジェクトからUNIXタイムを取得するには、「getTime」メソッドを使います。

 

developer.mozilla.org

 

getTime() メソッドは、協定世界時に基づく指定された日時の「時」に相当する数値を返します。

数値は、1970 年 1 月 1 日 00:00:00 UTC から指定した日時までの経過時間をミリ秒単位で表します。

 

注意点は、getTime()メソッドで得られる経過時間は、単位が「ミリ秒」になっていることです。

(1000ミリ秒=1秒)

UNIXタイムをベースにして計算する場合は、単位を秒に合わせるために、1000で割る必要がありますね。

 

syncer.jp

 

DateオブジェクトのgetTime()メソッドを実行すると、その時点でのUNIX時間を取得できます。

ただ、取得できるのはミリ秒単位なので、秒単位に直す場合は1000で除算(割り算)した上で、Math.floor()で少数以下を切り捨てます。

// Dateオブジェクトを作成 (引数なし)
var date = new Date() ;

// 現在のUNIX時間を取得する (ミリ秒単位)
var unixTimestamp = date.getTime() ;

// 現在のUNIX時間を取得する (秒単位)
var unixTimestamp = Math.floor( date.getTime() / 1000 ) ;

 

(例)未来の日時のUNIXタイムを取得する方法

// 2020年7月24日の13時30分00秒のDateオブジェクトを作成
var date = new Date( "2020-07-24 13:30:00" ) ;

// 未来のUNIX時間を取得する (ミリ秒単位)
var unixTimestamp = date.getTime() ;

// 未来のUNIX時間を取得する (秒単位)
var unixTimestamp = Math.floor( date.getTime() / 1000 ) ;

 

UNIXタイムを利用して時間の引き算

先のサンプルコードの部分で、経過時間の引き算を行っています。

var rest = due.getTime() - now.getTime();

 

残り時間 = 期限のUNIXタイム - 現在のUNIXタイム

という引き算で計算しています。

 

タイマー処理(一定時間で繰り返す)

1秒ごとに画面を再表示するなど、一定時間後に処理を実行したい場合には、JavaScriptであらかじめ用意されているsetTimeout()メソッドを使います。

 

サンプルコード

<!doctype html>
<html>
<head>
    <meta charset="UTF-8">
    <title>5-01_countdown</title>
</head>
<body>
    <h1>カウントダウンタイマー</h1>
    <h2>1秒ごとに再計算する</h2>
    <p>今から<span id="timer"></span>以内に注文すると50%オフ!</p>
    <script>
        var countdown = function (due) {
            var now = new Date();

            var rest = due.getTime() - now.getTime();
            var sec = Math.floor(rest / 1000 % 60);
            var min = Math.floor(rest / 1000 / 60) % 60;
            var hours = Math.floor(rest / 1000 / 60 / 60) % 24;
            var days = Math.floor(rest / 1000 / 60 / 60 / 24);
            var count = [days, hours, min, sec];

            return count;
        }

        var goal = new Date();
        goal.setHours(23);
        goal.setMinutes(59);
        goal.setSeconds(59);

        var recalc = function () {
            var counter = countdown(goal);
            var time = counter[1] + '時間' + counter[2] + '分' + counter[3] + '秒';
            document.getElementById('timer').textContent = time;
            refresh();
        }

        var refresh = function () {
            setTimeout(recalc, 1000);
        }

        recalc(); // 再計算
    </script>
</body>
</html>

 

実行結果

f:id:jsstudy:20170513013213p:plain

 

「今から~」の時刻表示が1秒ごとに更新されていました。

 

setTimeout()メソッドの使い方

(p.196)

setTimeoutは、「待ち時間」後に関数を1度だけ実行するメソッドです。

 

developer.mozilla.org

 

Web API インターフェイス > WindowTimers > window.setTimeout

指定された遅延の後に、コードの断片または関数を実行します。

 

書式:「待ち時間」後に関数を一度だけ実行する
setTimeout(関数, 待ち時間)

 

必要な引数が2つあります。

1つ目は実行する関数、2つ目はその関数を実行するまでの待ち時間をミリ秒で指定します。

1つ目の引数に指定する関数は、書き方の注意が必要です。

実行しようとしている関数名の後ろには、()をつけてはいけません。

 

関数名やメソッド名の後ろにつける()には、その関数やメソッドを「その場で実行する」という意味があります。

そのため、関数名の後ろに()をつけてしまうと、setTimeoutの処理が終わる前に、即座にrecalc関数が実行されてしまいます。

 

(参考)

note.onichannn.net

 

コールバック関数とは?

「関数に渡される関数」のことを「コールバック関数」と言います。

 

コールバック (情報工学) - Wikipedia

コールバック(英: Callback)とは、プログラミングにおいて、他のコードの引数として渡されるサブルーチンである。

 

qiita.com

 

コールバック(関数)とは

ひとことで言うと、「引数として渡される関数」です。

他関数の引数として使用し、特定のタイミングで実行させることができます。「あの処理が終わった後に、この関数を実行したい」など。

 

【JavaScript】コールバック(callback)関数とは何か?

コールバック関数とは?

引数として渡され、関数の中で所定のタイミングで実行される関数

 

関数の実行後にコールバック(呼び出される)関数。というイメージですね。

ですので、setTimeout()もコールバックを利用した関数になります。

 

上記のサンプルコードで、

setTimeout(recalc, 1000);

この「recalc」という関数が、「コールバック関数」です。

→ setTimeoutで1000ミリ秒(1秒)待つ処理を行った後に、setTimeoutから呼び出される(コールバックされる)関数が、recalcというわけです。

 

関数を呼び出すときに、いろいろな呼び出し方がありますが、「コールバック関数」も関数の呼び出し方(書き方)の一つです。

関数を引数にして、他の関数に渡せると、便利ですね!

どんなときにコールバック関数が役に立つのか?必要になるか?いろいろ調べてみましょう。

 

まとめ

  • 日時の設定は、Dateオブジェクトのセッターを使うか、初期化のときに日時データを指定する
  • UNIXタイムに変換すると、日時の足し算や引き算の計算ができる
  • setTimeout()メソッドで、タイマー処理(一定時間で繰り返し)が実現できる
  • setTimeout()メソッドで、コールバック関数を指定するときは書き方に注意(関数名の後ろに()を書かなくてOK)

 

日時の計算やタイマー処理を活用したいです。