【JavaScript】指定した時間に処理を行う方法

「15時30分になったら処理を実行したい」のように、JavaScriptで指定した時刻に処理を行う方法を解説します。

基本は目標時刻までの差(ミリ秒)を計算して setTimeout です。よくある「毎秒チェックする」方式は不要で、むしろ取りこぼしのリスクがあります。ブラウザのタイマーの限界や正しい毎日実行の書き方まで含めて解説します。

この記事の結論:目標時刻までの差を targetTime - Date.now() で求め、setTimeout でその時間後に実行します。毎秒ポーリングは不要です。毎日実行は発火時に翌日を再スケジュールします。ただしブラウザのタイマーは正確さを保証しないため、確実なスケジュールはサーバー側(cron)が必要です。
スポンサーリンク

指定時刻に1回実行する(setTimeout+差分計算)

もっとも確実なのは、今から目標時刻までの差(ミリ秒)を計算して、その時間後に setTimeout で実行する方法です。

JavaScript:指定時刻に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 → 発火したら翌日を再スケジュール」が確実です。毎回計算し直すので、ドリフトもたまりません。

JavaScript:毎日決まった時刻に実行
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ミリ秒)。これを超える遅延を渡すと即座に発火してしまいます
  • バックグラウンドタブはスロットリングされる。非アクティブなタブや端末のスリープ中は、タイマーが遅れたり止まったりします
JavaScript:長い遅延を分割して指定する
const MAX = 2147483647; // 約24.9日

function setLongTimeout(callback, delay) {
  if (delay > MAX) {
    setTimeout(() => setLongTimeout(callback, delay - MAX), MAX);
  } else {
    setTimeout(callback, delay);
  }
}
確実なスケジュールはサーバー側で:ブラウザのタイマーは、タブを閉じれば止まり、スリープ中は動きません。「必ずこの時刻に実行」が必要なら、サーバー側のcron(Node.jsのcronライブラリやOSのcron)で行います。ブラウザのタイマーは「開いている間の軽い予約」と考えましょう。タイマーの繰り返し全般はsetIntervalの完全ガイドを参照してください。

タイムゾーンに注意

new Date()setHours()実行環境のローカルタイムゾーンで動きます。サーバーとブラウザでタイムゾーンが違うと、指定時刻がずれることがあります。特定のタイムゾーンで動かしたいときは Intl.DateTimeFormat でタイムゾーンを指定するか、UTCを基準に計算します。時刻表示の実装はリアルタイム時計の作り方完全ガイド(タイムゾーン対応の章)も参考になります。

よくある質問(FAQ)

QJavaScriptで指定した時刻に処理を実行するには?
A現在時刻から目標時刻までのミリ秒を計算し、setTimeout でその時間後に実行します。例:const delay = targetTime - Date.now(); setTimeout(fn, delay)。毎秒チェックする必要はありません。
Q毎日同じ時刻に処理をするには?
A次回の実行時刻までの差を計算して setTimeout し、発火したら翌日を再スケジュールするのが確実です。「24時間ごとにsetInterval」より、毎回計算し直す方がDSTにも強くズレません。Node.jsではcronライブラリやOSのcronが信頼性が高いです。
Q指定時刻になっても処理が実行されないことがあります。
Aバックグラウンドのタブや端末のスリープ中は、タイマーがスロットリングされて遅れたり止まったりするためです。また setTimeout の遅延は約24.9日が上限で、超えると即発火します。確実に実行したいならサーバー側のcronを使ってください。
Qタイムゾーンを考慮した時刻処理をするには?
AIntl.DateTimeFormat でタイムゾーンを指定するか、UTCを基準に計算します。new Date はローカルタイムゾーンを使うため、UTCベースで処理してから表示時に変換するアプローチが管理しやすいです。

まとめ

指定時刻に処理を行うには、目標時刻までの差を setTimeout に渡すのが基本かつ確実です。毎秒・毎分のポーリングは取りこぼしの原因になるので避けましょう。毎日実行は発火時に翌日を再スケジュールする方式が堅実です。

ただしブラウザのタイマーには最大遅延(約24.9日)やタブのスロットリングといった制約があり、正確さは保証されません。「必ずこの時刻に」が必要ならサーバー側のcronを使い、タイムゾーンの違いにも注意しましょう。