にしし ふぁくとりー:西村文宏 個人サイト

"JavaScript Tips Factory" : Presented by Nishishi. Since 1997.

期限日時までをリアルタイムにカウントダウン表示する方法 [日付・時刻]

〆切(期限)日時まであとどのくらいの日数・時間が残っているのかをJavaScriptでリアルタイムにカウントダウン表示し続ける機能を作ってみましょう。現在日時と指定日時の差を求めて、差から残り日数・時刻を計算し、setIntervalメソッドを使って1秒ごとに表示を更新するだけで作れます。

期限日時までをリアルタイムにカウントダウン表示する方法

JavaScriptを使って、〆切(期限)日時まであとどのくらいの日数・時間があるのかをリアルタイムにカウントダウンし続ける機能を作ってみましょう。
指定の日時までにあと何ミリ秒あるのか?をJavaScriptで得る方法は、記事「指定日までの残り日数を計算して表示する」で解説しました。
また、一定間隔ごとに特定の処理を自動実行する方法は、記事「経過時間(秒数)をリアルタイムに表示する」で解説しました。
この2つを組み合わせれば、期限日時まで、ひたすらカウントダウンし続ける機能も簡単に作れます。
例えば、以下のように。サンプルとして日時が既に入っていますが、書き換えればその日時までをカウントダウンします。


※ここにカウントダウンが表示されます。

「上記の日時までカウントダウンする」ボタンをクリックすると、その瞬間に再計算されて表示します。……が、最初から1秒毎に自動更新しているので、ボタンを押さなくても最大1秒待つだけで再計算されてカウントダウン表示は更新されます。(^_^;)
上記でやっていることは、

  1. 現在日時を数値(1970-01-01 00:00:00からのミリ秒)に変換する。
  2. ユーザが入力した日時を取得して、数値(1970-01-01 00:00:00からのミリ秒)に変換する。
  3. 「現在日時の数値」と「指定日時の数値」を引き算して、日数(ミリ秒)の差を計算する。
  4. 差のミリ秒を、日数・時間・分・秒に分解して、カウントダウン表示用の文字列を作成する。
  5. 画面表示を更新。
  6. 上記1~5を、1秒毎に繰り返す。

という処理です。
他に、1桁の数字を2桁に調整する機能や、数字以外の文字が入力された場合には0として解釈する機能など、エラー対策も含んでいますが。

以下に、HTML+JavaScriptソースに関して簡単に解説してみます。(※解説をすっ飛ばして全体のソースを見たい場合は、本ページ末尾の項目「リアルタイムカウントダウン機能を作るHTML+JavaScriptソースのまとめ」へどうぞ。)

カウントダウン日付の入力欄と、カウントダウン掲載領域を作るHTMLソース

とりあえず、HTMLで以下の6個の入力欄を作っています。JavaScript側から参照するために、id属性を使って名前を付けています。

HTMLソース

<input type="text" id="userYear" >年
<input type="text" id="userMonth">月
<input type="text" id="userDate" >日
<input type="text" id="userHour" >時
<input type="text" id="userMin"  >分
<input type="text" id="userSec"  >秒

あと、実際にカウントダウンを表示するための領域を以下のように確保しています。

HTMLソース

<p id="RealtimeCountdownArea" >※ここにカウントダウンが表示されます。</p>

上記のid名「RealtimeCountdownArea」を使って、JavaScriptから表示を更新します。

現在日時と指定日時の差を求めて、残り日数・時間を計算するJavaScriptソース

指定日時までの残り時間をカウントダウンするためには、「指定日時」から「現在日時」を引き算する必要があります。
その辺の処理に関しては、記事「指定日までの残り日数を計算して表示する」で解説していますから、詳しくはそちらをご参照下さい。
ここでは、以下のようにJavaScriptソースを記述しています。
かなり冗長なソースですが、「何をやっているのか?」の分かりやすさを重視して、短くせずに記述しています。実際に活用する際は、もっと短く書いた方が良いと思います。^^;
……と言いつつ、エラー処理部分は省略しているのですが。そこを含めるとソースを解釈しにくくなりそうなので。^^;(末尾のソースまとめには記載しています。)

▼現在日時

JavaScriptソース

var nowDate = new Date();
var dnumNow = nowDate.getTime();

上記で、「現在日時」を数値(1970-01-01 00:00:00からのミリ秒)に変換して、変数dnumNowに格納しています。

▼ユーザの指定日時

JavaScriptソース

var inputYear  = document.getElementById("userYear").value;
var inputMonth = document.getElementById("userMonth").value - 1;
var inputDate  = document.getElementById("userDate").value;
var inputHour  = document.getElementById("userHour").value;
var inputMin   = document.getElementById("userMin").value;
var inputSec   = document.getElementById("userSec").value;
var targetDate = new Date( inputYear, inputMonth, inputDate, inputHour, inputMin, inputSec );
var dnumTarget = targetDate.getTime();

上記で、ユーザが入力した指定日時を、数値(1970-01-01 00:00:00からのミリ秒)に変換して、変数dnumTargetに格納しています。
Dateオブジェクトでは、月の指定は、「1月が0」・「2月が1」……「12月が11」になるので、1を引いています。

▼差を計算

JavaScriptソース

var diff2Dates = dnumTarget - dnumNow;
if( dnumTarget < dnumNow ) {
   // 期限が過ぎた場合は -1 を掛けて正の値に変換
   diff2Dates *= -1;
}

上記で、2つの変数を引き算して、日数(ミリ秒)の差を計算しています。
期限が過ぎている場合はマイナスの値になるので、その場合には -1 を掛けて正の値にしています。

▼ミリ秒を分解

JavaScriptソース

var dDays  = diff2Dates / ( 1000 * 60 * 60 * 24 );	// 日数
diff2Dates = diff2Dates % ( 1000 * 60 * 60 * 24 );
var dHour  = diff2Dates / ( 1000 * 60 * 60 );	// 時間
diff2Dates = diff2Dates % ( 1000 * 60 * 60 );
var dMin   = diff2Dates / ( 1000 * 60 );	// 分
diff2Dates = diff2Dates % ( 1000 * 60 );
var dSec   = diff2Dates / 1000;	// 秒

上記で、「差のミリ秒」を、日数・時間・分・秒に分解しています。
「割った解」と「割った余り」を使っていくことで、日→時→分→秒の順に抜き出しています。
日数は変数dDaysに、時間は変数dHourに、分は変数dMinに、秒は変数dSecに入ります。
なんかもうちょっとスマートな方法があるような気がしますが(^_^;)、まあ上記でもちゃんと計算はできます。

カウントダウンの画面表示文字列を作るJavaScriptソース

次に、計算結果を画面に表示する必要があります。
冒頭のサンプルでは、ユーザが入力した日時も含めて表示しています。
それらのソースは以下の通りです。

▼期限日時を表示

JavaScriptソース

var dlYear  = targetDate.getFullYear();
var dlMonth = targetDate.getMonth() + 1;
var dlDate  = targetDate.getDate();
var dlHour  = targetDate.getHours();
var dlMin   = targetDate.getMinutes();
var dlSec   = targetDate.getSeconds();
var msg1 = "期限の" + dlYear + "/" + dlMonth + "/" + dlDate + " " + dlHour + ":" + dlMin + ":" + dlSec;

上記で、変数msg1に、ユーザが指定した日時が文字列として格納されます。
実際には、「1桁の数字を2桁固定にする」処理を含んでいますが、上記では見た目を簡単にするために省略しています。
先も述べましたが、月は「1月が0」・「2月が1」……「12月が11」になっているので、ここでは1を足しています。
ユーザが入力した文字列を直接は利用せずに、カウントダウン計算用のDateオブジェクトから日付を求めているのは、ユーザの入力内容をそのまま出力する危険を避けるためです。

▼残り日数・時間を表示

JavaScriptソース

var msg2 = Math.floor(dDays) + "日"
         + Math.floor(dHour) + "時間"
         + Math.floor(dMin) + "分"
         + Math.floor(dSec) + "秒";

上記で、変数msg2に、残り日数・時間が文字列として格納されます。ここがカウントダウンのメインです。
なお、Math.floorは、小数点以下を取り去る関数です。これがないと、小数点以下がずらーっと並んでしまいます。
ソースを見やすくするために改行していますが、全部を1行で書いても問題ありません。

▼カウントダウンかカウントアップの文字列を作成するJavaScriptソース

JavaScriptソース

var msg;
if( dnumTarget > dnumNow ) {
   // まだ期限が来ていない場合
   msg = msg1 + "までは、あと" + msg2 + "です。";
}
else {
   // 期限が過ぎた場合
   msg = msg1 + "は、既に" + msg2 + "前に過ぎました。";
}

上記で、画面表示用の文字列を作成し、変数msgに格納しています。
「期限が来ていない」場合と「期限が過ぎた場合」とで表現を変える必要があったので、if文で条件分岐させています。

JavaScriptソース

document.getElementById("RealtimeCountdownArea").innerHTML = msg;

最後に、上記のようにinnerHTMLメソッドを使って、作成した文字列を(id名「RealtimeCountdownArea」の領域に)表示しています。
上記の一連の処理を、「showCountdown」という名称で関数にしておけば完成です。(全体のソースは後述)

1秒ごとに処理を繰り返すことで、リアルタイムにカウントダウンする処理

上記で作成したソースを、1秒毎に繰り返し自動実行することで、「リアルタイムのカウントダウン」が実現します。
一定間隔ごとに特定の処理を自動実行する方法は、記事「経過時間(秒数)をリアルタイムに表示する」で解説しましたから、詳しくはそちらをご参照下さい。
ここでは、以下のように1行を書いただけです。

setInterval('showCountdown()',1000);

これで、1000ミリ秒(=1秒)ごとにshowCountdown関数が実行されます。

リアルタイムカウントダウン機能を作るHTML+JavaScriptソースのまとめ

基本的に今回のサンプルは、2つの記事で解説済みの内容を組み合わせただけです。
なので、説明はあまり詳しくは書きませんでした。
全体的に対して難しくないので、ソースを読んで頂ければ簡単に分かるとは思いますが。(^_^;)
以下に、すべてのソース(HTML+JavaScript)をまとめて掲載しておきます。上記では省略した、桁数調整や入力エラー対策の関数も含んでいます。

HTMLソース

<p>
   <input type="text" id="userYear"  maxlength="4">年
   <input type="text" id="userMonth" maxlength="2">月
   <input type="text" id="userDate"  maxlength="2">日
   <input type="text" id="userHour"  maxlength="2">時
   <input type="text" id="userMin"   maxlength="2">分
   <input type="text" id="userSec"   maxlength="2">秒<br>
   <input type="button" value="上記の日時までカウントダウンする" onclick="showCountdown();">
</p>
<p id="RealtimeCountdownArea">※ここにカウントダウンが表示されます。</p>

JavaScriptソース

function set2fig(num) {
   // 数値が1桁だったら2桁の文字列にして返す
   var ret;
   if( num < 10 ) { ret = "0" + num; }
   else { ret = num; }
   return ret;
}
function isNumOrZero(num) {
   // 数値でなかったら0にして返す
   if( isNaN(num) ) { return 0; }
   return num;
}
function showCountdown() {
   // 現在日時を数値(1970-01-01 00:00:00からのミリ秒)に変換
   var nowDate = new Date();
   var dnumNow = nowDate.getTime();

   // 指定日時を数値(1970-01-01 00:00:00からのミリ秒)に変換
   var inputYear  = document.getElementById("userYear").value;
   var inputMonth = document.getElementById("userMonth").value - 1;
   var inputDate  = document.getElementById("userDate").value;
   var inputHour  = document.getElementById("userHour").value;
   var inputMin   = document.getElementById("userMin").value;
   var inputSec   = document.getElementById("userSec").value;
   var targetDate = new Date( isNumOrZero(inputYear), isNumOrZero(inputMonth), isNumOrZero(inputDate), isNumOrZero(inputHour), isNumOrZero(inputMin), isNumOrZero(inputSec) );
   var dnumTarget = targetDate.getTime();

   // 表示を準備
   var dlYear  = targetDate.getFullYear();
   var dlMonth = targetDate.getMonth() + 1;
   var dlDate  = targetDate.getDate();
   var dlHour  = targetDate.getHours();
   var dlMin   = targetDate.getMinutes();
   var dlSec   = targetDate.getSeconds();
   var msg1 = "期限の" + dlYear + "/" + dlMonth + "/" + dlDate + " " + set2fig(dlHour) + ":" + set2fig(dlMin) + ":" + set2fig(dlSec);

   // 引き算して日数(ミリ秒)の差を計算
   var diff2Dates = dnumTarget - dnumNow;
   if( dnumTarget < dnumNow ) {
      // 期限が過ぎた場合は -1 を掛けて正の値に変換
      diff2Dates *= -1;
   }

   // 差のミリ秒を、日数・時間・分・秒に分割
   var dDays  = diff2Dates / ( 1000 * 60 * 60 * 24 );   // 日数
   diff2Dates = diff2Dates % ( 1000 * 60 * 60 * 24 );
   var dHour  = diff2Dates / ( 1000 * 60 * 60 );   // 時間
   diff2Dates = diff2Dates % ( 1000 * 60 * 60 );
   var dMin   = diff2Dates / ( 1000 * 60 );   // 分
   diff2Dates = diff2Dates % ( 1000 * 60 );
   var dSec   = diff2Dates / 1000;   // 秒
   var msg2 = Math.floor(dDays) + "日"
            + Math.floor(dHour) + "時間"
            + Math.floor(dMin) + "分"
            + Math.floor(dSec) + "秒";

   // 表示文字列の作成
   var msg;
   if( dnumTarget > dnumNow ) {
      // まだ期限が来ていない場合
      msg = msg1 + "までは、あと" + msg2 + "です。";
   }
   else {
      // 期限が過ぎた場合
      msg = msg1 + "は、既に" + msg2 + "前に過ぎました。";
   }

   // 作成した文字列を表示
   document.getElementById("RealtimeCountdownArea").innerHTML = msg;
}
// 1秒ごとに実行
setInterval('showCountdown()',1000);

上記では、一定時間毎に処理を繰り返すsetIntervalメソッドをいきなり実行しているので、スクリプトの読み込みと同時に処理が開始されます。
それを避けたい場合は、setIntervalメソッドも何らかの関数の内側に記述して下さい。記事「経過時間(秒数)をリアルタイムに表示する」では、ボタンをクリックするまでsetIntervalメソッドを実行しない書き方をしています。
showCountdown関数を実行するためのボタンも用意していますが、押さなくても1秒ごとに自動実行されるので、まあ不要です。(^_^;)
ページの読込と同時にカウントダウンを実行させるのでないのなら、カウントダウンを開始するボタンが必要ですが。

ミリ秒まで表示させてカウントダウンしたい場合

なお、期限日時が来たとき、「残り0日0時間0分0秒です」→「0日0時間0分0秒前に過ぎました」で、合計2秒間あるように見えます。
なぜこうなるのかは、ミリ秒まで表示させてみるとよく分かります。(^_^;;;

  • 残り1秒000 → 「残り1秒です」と表示
  • 残り0秒999 → 「残り0秒です」と表示
  • 残り0秒001 → 「残り0秒です」と表示
  • 0秒001経過 → 「0秒前に過ぎました」と表示
  • 0秒999経過 → 「0秒前に過ぎました」と表示
  • 1秒000経過 → 「1秒前に過ぎました」と表示

上記のようになるので、「指定日時まで残り1秒を切った後」から「指定日時から1秒が経過する直前」までの2秒間は、「0秒」の表示になります。
若干、不思議な感じがするので、それを避けたければ、ミリ秒まで含めて表示するのも良いかも知れません。
変数msg2を作る行を以下のようにした上で、

JavaScriptソース

var dMiSec = diff2Dates % 1000;
var msg2 = Math.floor(dDays) + "日"
         + Math.floor(dHour) + "時間"
         + Math.floor(dMin) + "分"
         + Math.floor(dSec) + "秒"
         + dMiSec;

以下のように、setIntervalメソッドを1秒よりももっと短い間隔で呼び出します。

setInterval('showCountdown()',200);

上記の場合は、200ミリ秒(=0.2秒)ごとに描画が更新されます。
ただ、あまり更新頻度を上げてしまうと、処理が重たくなってしまう可能性がありますから、あんまり頻度を上げすぎない(=数値を低くし過ぎない)方が良いとは思います。

……というわけで、なんだかほとんどソースだけを掲載したような感じですが。(^_^;)
まあ、解説は冒頭でリンクしている2本の記事に書いていますからね。^^; 重複分を除けば、ほとんど説明することなんてないので。(^_^;;;
ユーザの指定した日時までの残り日数・時間をリアルタイムにカウントダウンする機能の作り方でした。(期限が過ぎた場合は、カウントダウンではなくカウントアップですが。^^;)
ぜひ、何かに活用してみて下さい。(^_^;)

()

JavaScript TIPSふぁくとりーの主要なカテゴリ

下記のカテゴリに区分して、JavaScriptに関するTIPSを公開しています。カッコ内の数字は、該当する記事の件数です。

著者紹介


にしし(西村文宏)

にししでございます。本書いたり記事書いたりしてます。あと萌えたり。著書5冊発売中です(Web製作系4冊+小説1冊)。著書や記事は「西村文宏」名義。記事は主にAll Aboutで連載。本の最新刊は2011年3月に発売されたライトノベルでございますよ。

Twitter:にしし/西村文宏
にしし/西村文宏 on facebook にしし/西村文宏 on mixi フォローはお気軽に!

にしし(西村文宏)連絡先
☕ コーヒーをおごる

著書一覧と詳細

関連するかもしれない情報など

▼このページに関連しそうな記事が約8本くらい自動表示されています。(たぶん)

--- 当サイト内を検索 ---