VBAには本来の非同期処理がないため、Application.OnTimeで疑似的にタイマー処理を組もうとして何度もハマりました。実行中のブックが閉じられた時の挙動など、ドキュメントだけでは分からない制約を中心に記録しています。

OnTime の構文

VBA OnTimeタイマー図

図1: Application.OnTime の定期実行フロー

VBA — OnTime 構文
' Application.OnTime EarliestTime, Procedure, [LatestTime], [Schedule]
' EarliestTime : 実行する時刻(Date型)
' Procedure    : 実行するプロシージャ名(文字列)
' Schedule     : True=登録(既定)/ False=キャンセル

指定時刻に1回実行

VBA — 30秒後に実行
Option Explicit

Sub ScheduleOnce()
    ' 30秒後に DoTask を実行
    Application.OnTime Now + TimeValue("00:00:30"), "DoTask"
End Sub

Sub DoTask()
    MsgBox "30秒後の処理が実行されました: " & Now
End Sub

一定間隔で定期実行

VBA — 10秒ごとに定期実行
Option Explicit

Private g_NextTime As Date
Private g_Running  As Boolean

Sub StartTimer()
    g_Running  = True
    g_NextTime = Now + TimeValue("00:00:10")
    Application.OnTime g_NextTime, "TimerTick"
    MsgBox "タイマー開始"
End Sub

Sub TimerTick()
    If Not g_Running Then Exit Sub

    ' ── 定期処理 ──
    Debug.Print "実行: " & Now
    ThisWorkbook.Sheets(1).Cells(1, 1).Value = Now

    ' 次回を予約
    g_NextTime = Now + TimeValue("00:00:10")
    Application.OnTime g_NextTime, "TimerTick"
End Sub

Sub StopTimer()
    g_Running = False
    On Error Resume Next
    Application.OnTime g_NextTime, "TimerTick", Schedule:=False
    On Error GoTo 0
    MsgBox "タイマー停止"
End Sub

タイマーのキャンセル

Schedule:=False で登録済みのタイマーをキャンセルできます。同一の時刻とプロシージャ名を指定する必要があります。

制約と注意事項

制約内容
Excelが開いている必要ありExcelを閉じるとタイマーは無効化される
マクロ実行中はキューイング他のマクロ実行中は OnTime の時刻が来てもキューに積まれ、完了後に実行される
精度は1秒単位ミリ秒以下の精度は出ない
引数なしプロシージャのみ引数付きプロシージャは直接指定できない(グローバル変数経由で代替)
キャンセル時の注意タイマー時刻を変数に保持しておかないとキャンセルできない

⚠️ ブックを閉じる前にタイマーを必ず停止する

Workbook_BeforeCloseStopTimer を呼び出すか、g_Running = False を設定してください。停止せずに閉じると次回開いたときに意図しない実行が起きる場合があります。

Application.OnTimeの活用パターン

業務Excelで実際に使われる定期処理の用途と、実装時の注意点をまとめる。

活用シナリオ実装のポイント注意点
外部データの定期取得(株価・為替・APIレスポンス) TimerTick内でHTTPリクエストを発行しセルに書き込む。次回を再スケジュールして繰り返す APIレスポンスが遅延すると次回スケジュールがずれる。Timeoutを設定しておく
一定時間後の自動保存 Now + TimeValue("00:05:00")で5分後にThisWorkbook.Saveを呼ぶ 保存ダイアログが出ないようDisplayAlerts = Falseを設定する
処理の分割実行(大量データを少しずつ処理) 処理済み行番号をグローバル変数で持ち、OnTimeで次のチャンクを処理 途中でExcelを操作されると競合が起きる。処理中はUIをロックする工夫が必要
アラート通知(閾値超え時にメッセージを表示) 監視対象セルを定期チェックし、閾値超えでMsgBoxまたはテキスト書き込み MsgBoxはモーダルのため次回タイマーがキューに積まれる。非モーダル表示を検討

まとめ

Application.OnTime は定期実行ツールや自動保存・自動更新処理に有効です。ただし「Excelを閉じると止まる」「精度1秒」「引数なし限定」という制約を理解したうえで使いましょう。

次の章では…

PART 13 では API呼び出し を解説します。Declare Function でWin32 APIを呼び出し、64bit対応の PtrSafe についても解説します。

→ PART 13 — API呼び出しへ

Application.OnTimeでよくある誤り

OnTimeによるタイマー処理は便利ですが、Excelのライフサイクルや制約を理解せずに使うと予期しない動作になります。

誤り/失敗パターン何が起きるか正しい対処/防止策
OnTimeのキャンセル処理を書かないブックを閉じた後もタイマーが残り、次回Excel起動時にエラーが発生するWorkbook_BeforeCloseでApplication.OnTime EarliestTime:=nextTime, Procedure:="...", Schedule:=Falseでキャンセルする
Excelが閉じられてもタイマーが動くと思い込むExcelを閉じるとOnTimeスケジュールはすべてキャンセルされ、定期実行が止まるバックグラウンド実行が必要ならWindowsタスクスケジューラ+VBScriptやPowerShellで実装する
引数ありのプロシージャをOnTimeで直接指定するOnTimeはプロシージャ名の文字列指定のため引数を渡せず、エラーになる引数をグローバル変数やPublic変数で渡すか、引数なしのラッパープロシージャを作成してOnTimeで呼び出す