「15時30分になったら処理を実行したい」のように、JavaScriptで指定した時刻に処理を行う方法を解説します。
基本は目標時刻までの差(ミリ秒)を計算して setTimeout です。よくある「毎秒チェックする」方式は不要で、むしろ取りこぼしのリスクがあります。ブラウザのタイマーの限界や正しい毎日実行の書き方まで含めて解説します。
targetTime - Date.now() で求め、setTimeout でその時間後に実行します。毎秒ポーリングは不要です。毎日実行は発火時に翌日を再スケジュールします。ただしブラウザのタイマーは正確さを保証しないため、確実なスケジュールはサーバー側(cron)が必要です。指定時刻に1回実行する(setTimeout+差分計算)
もっとも確実なのは、今から目標時刻までの差(ミリ秒)を計算して、その時間後に setTimeout で実行する方法です。
function runAt(targetTime, task) {
const delay = targetTime.getTime() - Date.now();
if (delay <= 0) {
console.log("指定時刻は過ぎています");
return;
}
setTimeout(task, delay);
}
// 今日の15:30に実行
const target = new Date();
target.setHours(15, 30, 0, 0);
runAt(target, () => {
console.log("指定時刻に処理を実行します");
});
setTimeout の詳細はsetTimeout関数による遅延実行の手引きで解説しています。
毎秒チェック(ポーリング)を避ける
古い記事では setInterval で毎秒・毎分チェックして、現在時刻が目標時刻に一致したら実行する方式をよく見かけますが、おすすめしません。
setInterval(fn, 1000) は実行のたびにわずかにずれ(ドリフト)が生じ、getSeconds() === 目標 のような完全一致は対象の瞬間を取りこぼすことがあります。毎分チェックも同様で、二重実行や取りこぼしが起きえます。差分を計算する setTimeout 方式なら、こうした問題が起きません。毎日決まった時刻に実行する(再スケジュール方式)
毎日同じ時刻に実行したいときも、ポーリングではなく「次回の時刻までの差を setTimeout → 発火したら翌日を再スケジュール」が確実です。毎回計算し直すので、ドリフトもたまりません。
function scheduleDaily(hour, minute, task) {
const now = new Date();
const next = new Date();
next.setHours(hour, minute, 0, 0);
// 今日の時刻が過ぎていたら翌日にする
if (next <= now) {
next.setDate(next.getDate() + 1);
}
const delay = next.getTime() - now.getTime();
setTimeout(() => {
task();
scheduleDaily(hour, minute, task); // 次の日を再スケジュール
}, delay);
}
scheduleDaily(15, 30, () => {
console.log("毎日15:30に処理を実行します");
});
「24時間ごと」と固定で setInterval するより、毎回次回時刻を計算するこの方式のほうがサマータイム(DST)のある地域でもズレません。
注意点(最大遅延・タブのスロットリング)
ブラウザの setTimeout / setInterval には、正確なスケジューリングを妨げるいくつかの制約があります。
- 最大遅延は約24.9日(
2147483647ミリ秒)。これを超える遅延を渡すと即座に発火してしまいます - バックグラウンドタブはスロットリングされる。非アクティブなタブや端末のスリープ中は、タイマーが遅れたり止まったりします
const MAX = 2147483647; // 約24.9日
function setLongTimeout(callback, delay) {
if (delay > MAX) {
setTimeout(() => setLongTimeout(callback, delay - MAX), MAX);
} else {
setTimeout(callback, delay);
}
}
タイムゾーンに注意
new Date() や setHours() は実行環境のローカルタイムゾーンで動きます。サーバーとブラウザでタイムゾーンが違うと、指定時刻がずれることがあります。特定のタイムゾーンで動かしたいときは Intl.DateTimeFormat でタイムゾーンを指定するか、UTCを基準に計算します。時刻表示の実装はリアルタイム時計の作り方完全ガイド(タイムゾーン対応の章)も参考になります。
よくある質問(FAQ)
setTimeout でその時間後に実行します。例:const delay = targetTime - Date.now(); setTimeout(fn, delay)。毎秒チェックする必要はありません。setTimeout し、発火したら翌日を再スケジュールするのが確実です。「24時間ごとにsetInterval」より、毎回計算し直す方がDSTにも強くズレません。Node.jsではcronライブラリやOSのcronが信頼性が高いです。setTimeout の遅延は約24.9日が上限で、超えると即発火します。確実に実行したいならサーバー側のcronを使ってください。Intl.DateTimeFormat でタイムゾーンを指定するか、UTCを基準に計算します。new Date はローカルタイムゾーンを使うため、UTCベースで処理してから表示時に変換するアプローチが管理しやすいです。まとめ
指定時刻に処理を行うには、目標時刻までの差を setTimeout に渡すのが基本かつ確実です。毎秒・毎分のポーリングは取りこぼしの原因になるので避けましょう。毎日実行は発火時に翌日を再スケジュールする方式が堅実です。
ただしブラウザのタイマーには最大遅延(約24.9日)やタブのスロットリングといった制約があり、正確さは保証されません。「必ずこの時刻に」が必要ならサーバー側のcronを使い、タイムゾーンの違いにも注意しましょう。

