JavaScriptのsetIntervalで表示した時計がずれるのを合わせる方法

JavaScriptのsetIntervalで表示した時計がずれるのを合わせる方法

突然ですが、あなたの実装した時計ずれていませんか

ページに現在の日付と時間を表示させることはよくあっても、JavaScript(js)を使ってリアルタイム且つ秒数までの表示させるってことはありそうであまりありません。それでもあります。笑

何が言いたいかというとsetintervalには罠が隠れています。これを知らないといざsetintervalを使用して表示した時計が最大で≒1秒ずれた時計表示になってしまいます。たかがそれぐらいと思うかもしれないですが凄く気持ち悪いです。

今回は、そんなWEBページにJavaScriptのsetinterval使用してズレのない時計(正確にはあるが気にならないほど)を表示する方法をご紹介します。

setIntervalで表示した時計は実際の時刻よりタイミングが遅れる

まずは、やりがちな失敗例から見ていきましょう。

setInterval("showClock()", 1000);

function showClock() {
  var dd = new Date();
  var date_text = dd.getFullYear() + "年";
  date_text += ('0' + (dd.getMonth() + 1)).slice(-2) + "月";
  date_text += ('0' + dd.getDate()).slice(-2) + "日";
  
  var time_text = ('0' + dd.getHours()).slice(-2) + ":";
  time_text += ('0' + dd.getMinutes()).slice(-2) + ":";
  time_text += ('0' + dd.getSeconds()).slice(-2);
  document.getElementById("nowdate").innerHTML = date_text;
  document.getElementById("nowtime").innerHTML = time_text;
}

今回はHTMLやCSSなどは直接関係ないので割愛させてもらいますが、こんな感じのシンプルな時計が表示されるとします。

JavaScriptのコードを見てもらうと関数”showClock()”は時計を表示しており、それをsetInterval()で1秒毎に実行しているというのが分かると思います。

一見すると1秒毎に表示されている時間が更新されて何の問題もないように思いますがページを開いたタイミングによっては実際の時間とは最大≒1秒遅れてしまいます。0.1秒ずれただけでも実際の時計と並んだ時にこのように秒数の表示タイミングがずれるので思っている以上に気持ちが悪いことなのです。

setIntervalでタイミングがずれる理由

理由はすごく単純で秒の下にも単位(ミリ秒)があるからです。普段生活しているなかで1秒より下の単位なんか気にして生きている人はほどんどいないと思います。気にしている人と言ったら競技をしているか、ちょっと変わりものくらいです。笑

ただ、気にしないだけで1秒から2秒かわるときは「1.0秒, 1.1秒, 1.2秒…..1.9秒, 2.0秒」と変わっていきます。もちろんもっと下の位もあります。このことを頭に入れておいてください。

setInterval("showClock()", 1000);

そしてこのsetIntervalの書き方だと、ページが表示されたタイミングから1秒毎に実行という記述になっています。感のいい人はもうわかりましたよね?

もしページが開かれたタイミング(時間)が1.0秒だったら問題ないのですが、1.5秒のときにページがひらかれたとしたら「2.5秒, 3.5秒, 4.5秒…..」 というように0.5秒ずれた時刻で実行されていきます。つまり実際の時刻より0.5秒遅れた時計が完成してしまいます。これがsetIntervalの罠で使用するときに注意が必要な理由です。

setTimeoutで実行タイミングをミリ秒単位で合わせる

タイミングがずれる理由さえわかっていれば修正するのは簡単です!setIntervalを実行するタイミングをミリ秒を実際の時刻と合わせてあげればいいのです。実際にタイミングを修正したものがこちらです。

showClock();
 
setTimeout(function () {
   showClock();
   setInterval("showClock()", 1000);
}, 1000 - new Date().getUTCMilliseconds() );

ここでポイントになるのが6行目の「1000 – new Date().getUTCMilliseconds()」で指定しているsetTimeoutの実行タイミングです。

簡単に説明すると「new Date().getUTCMilliseconds()」は現在時刻のミリ秒を表す 0 から 999 までの間の整数を取得することができます。なので1000から現在時刻のミリ秒を引いた値は、次にちょうどX.000秒になるまでのミリ秒数を取得することができます。

例として、現在の時間が5.200秒だとすると「new Date().getUTCMilliseconds()」で取得できる値は「200」となります。1000 – 200 = 800(0.800秒)となるのでsetTimeoutで実行されるのは0.8秒後、つまり6.000秒ジャストとなるわけです!

そのタイミングで5行目setIntervalで1秒毎に実行することで 7.000秒 ,8.000秒 ,9.000秒のタイミングで実行されるようにセットされます。

1行目、4行目で”showClock();”を実行している理由は表示までのタイムラグを無くすためです。これにより実際の時刻とズレのない時計が完成します!

setIntervalを使う時はsetTimeoutとセット使用を検討する!

この考え方がわかれば、秒が切り替わったときはもちろん、1分,2分,3分…のように分が切り替わったタイミングでの実行なども対応可能になります!

“setInterval”は単純に毎秒、毎分に実行することはできますが、“setTimeout”と併用してタイミングを調節してあげることでさらに利用範囲は広がります!
機能によっては”setInterval”と”setTimeout”の併用を検討してください!