🚀The world's best VBA AI has evolved. ExcelMaster is now an autonomous Agent.Read more →
Back to Blog

VBA OnTime dans Excel — exécuter une macro à heure fixe ou toutes les N minutes, et vraiment l'arrêter

|

VBA OnTime dans Excel — exécuter une macro à heure fixe ou toutes les N minutes, et vraiment l'arrêter

TL;DR — Application.OnTime ne lance pas de minuteur. Il dépose une réservation dans la file d'Excel : à telle heure, exécute telle macro. Votre code se termine aussitôt et Excel reste utilisable ; quand l'heure arrive et qu'Excel est disponible, il exécute la macro. La réservation est identifiée par l'heure exacte et le nom de la macro : pour l'annuler, il faut repasser les deux, ce qui impose de conserver l'heure dans une variable de niveau module. Pour une tâche répétitive, la macro réserve elle-même sa prochaine exécution. Annulez dans Workbook_BeforeClose, car fermer le classeur n'annule rien : Excel rouvrira le fichier pour honorer le rendez-vous.

Private mNextRun As Date                       ' la reservation qu'il faudra peut-etre annuler

Sub StartRefresh()
    mNextRun = Now + TimeSerial(0, 5, 0)       ' dans cinq minutes
    Application.OnTime mNextRun, "RefreshPrices"
End Sub

Sub StopRefresh()
    On Error Resume Next                       ' erreur 1004 si rien n'est reserve
    Application.OnTime mNextRun, "RefreshPrices", Schedule:=False
    On Error GoTo 0
End Sub

Voici le deuxième article d'une série consacrée aux macros qu'Excel lance pour vous. Le guide des touches de raccourci traite des macros lancées au clavier, et le guide SendKeys des frappes simulées. L'idée qui les relie : aucun de ces mécanismes n'appelle votre macro directement. Chacun dépose une demande dans la file d'Excel, et Excel l'exécute quand il est inactif et disponible. Avec OnTime, la demande porte une heure, et elle reste dans la file jusqu'à ce qu'elle s'exécute ou que vous la retiriez avec exactement les mêmes informations.

Ce que vous allez apprendre

  • Le modèle mental : une réservation, pas un minuteur qui tourne
  • Exécuter une macro à une heure de la journée, et toutes les N minutes
  • Pourquoi l'annulation échoue, et la variable qui règle le problème
  • Le minuteur impossible à arrêter après une réinitialisation du code
  • Pourquoi fermer le classeur pousse Excel à le rouvrir
  • Un Excel occupé, LatestTime, et un planning qui dérive
  • Quand OnTime n'est pas le bon outil

Le modèle mental : une réservation, pas un minuteur

Comparez OnTime à une boucle qui attend :

' Bloque Excel : plus rien ne peut se passer pendant cinq minutes
Application.Wait Now + TimeSerial(0, 5, 0)
RefreshPrices

' Depose une reservation et rend la main aussitot : Excel reste utilisable
Application.OnTime Now + TimeSerial(0, 5, 0), "RefreshPrices"

Application.Wait et Sleep gardent votre macro en exécution et Excel figé. OnTime remet un mot à Excel et s'arrête là. Entre maintenant et l'heure réservée, aucun code VBA ne tourne ; l'utilisateur travaille normalement.

Excel tient une liste de ces réservations. Chaque entrée a deux clés, une date-heure et un nom de procédure, et Excel retrouve une entrée en faisant correspondre les deux. Tout le reste de cet article en découle : vous pouvez en réserver plusieurs, vous en annulez une en la désignant exactement, et la liste appartient à Excel, pas à votre classeur.

Exécuter une macro à une heure de la journée

Donnez à OnTime une date et une heure complètes, pour qu'il n'y ait aucun doute sur le jour visé :

Sub BookDailyExport()
    Dim runAt As Date
    runAt = Date + TimeSerial(17, 0, 0)        ' aujourd'hui a 17:00
    If runAt <= Now Then runAt = runAt + 1     ' deja passe : demain a 17:00
    Application.OnTime runAt, "DailyExport"
End Sub

Beaucoup d'exemples ne passent que TimeValue("17:00:00"). Construire la date vous-même rend la règle visible dans le code : si l'heure est passée, la prochaine exécution a lieu demain, pas tout de suite. Le guide Now explique pourquoi Date plus une heure donne une vraie valeur date-heure, et TimeSerial met le calcul à l'abri des problèmes de paramètres régionaux, un vrai sujet sur un poste français où l'on écrit 17:00 mais aussi 03/10/2026.

Exécuter une macro toutes les N minutes

Il n'existe pas d'option de répétition. Une tâche répétitive est une macro qui réserve elle-même sa prochaine exécution à la fin :

Private mNextRun As Date
Private Const INTERVAL_MIN As Long = 5

Sub StartRefresh()
    mNextRun = Now + TimeSerial(0, INTERVAL_MIN, 0)
    Application.OnTime mNextRun, "RefreshPrices"
End Sub

Sub RefreshPrices()
    ThisWorkbook.Worksheets("Prices").Range("A1").CurrentRegion.Calculate
    ' ... le vrai travail ...
    StartRefresh                               ' reserver l'execution suivante
End Sub

StartRefresh démarre la chaîne et RefreshPrices l'entretient. Pour arrêter la chaîne, il faut retirer l'unique réservation actuellement en place, et c'est là que la plupart des codes OnTime échouent.

Annuler : l'heure exacte, ou l'erreur 1004

Pour annuler, appelez de nouveau OnTime avec Schedule:=False. Excel cherche alors une entrée avec la même heure et le même nom de procédure. Ceci a l'air juste et ne fonctionne pas :

' Faux : Now a avance, cette heure ne correspond a aucune reservation
Application.OnTime Now + TimeSerial(0, 5, 0), "RefreshPrices", Schedule:=False

Aucune réservation n'existe à cette nouvelle heure : Excel lève donc Run-time error 1004: Method 'OnTime' of object '_Application' failed (en français : « Erreur d'exécution 1004 : La méthode 'OnTime' de l'objet '_Application' a échoué »), et la vraie réservation reste en place. C'est pour cela que l'heure vit dans une variable de niveau module (mNextRun ci-dessus). Réservez avec elle, annulez avec elle, et les informations correspondent toujours.

Le On Error Resume Next de StopRefresh est volontaire et ne couvre qu'une ligne : si rien n'est réservé, par exemple parce que la macro s'est déjà exécutée, l'annulation lève l'erreur 1004 et il n'y a rien d'autre à faire. Le guide On Error explique pourquoi garder un tel gestionnaire aussi étroit.

Le minuteur impossible à arrêter

La variable a un point faible. Les variables de niveau module sont effacées chaque fois que le projet VBA est réinitialisé : quand vous cliquez sur le bouton Réinitialiser, quand une erreur non gérée met fin au code, quand le code exécute End, ou quand vous modifiez le code pendant qu'il est en pause. Le guide des variables globales les recense toutes.

Après une réinitialisation, mNextRun vaut 0. La réservation est toujours dans la liste d'Excel, mais votre code ne connaît plus son heure : StopRefresh n'annule donc rien. La macro continue de s'exécuter toutes les cinq minutes et se réserve de nouveau à chaque passage.

Gardez une copie de l'heure à un endroit qui survit à une réinitialisation, par exemple une cellule d'une feuille de paramètres masquée :

Sub StartRefresh()
    mNextRun = Now + TimeSerial(0, INTERVAL_MIN, 0)
    ThisWorkbook.Worksheets("Settings").Range("B2").Value = mNextRun
    Application.OnTime mNextRun, "RefreshPrices"
End Sub

Sub StopRefresh()
    If mNextRun = 0 Then mNextRun = ThisWorkbook.Worksheets("Settings").Range("B2").Value
    On Error Resume Next
    Application.OnTime mNextRun, "RefreshPrices", Schedule:=False
    On Error GoTo 0
    mNextRun = 0
End Sub

Si un minuteur s'emballe malgré tout pendant le développement, fermer complètement Excel vide la liste.

Fermer le classeur n'annule rien

La réservation appartient à Excel, pas au classeur. Si l'utilisateur ferme votre classeur et qu'Excel reste ouvert, Excel rouvre le classeur à l'heure réservée pour exécuter la macro. Pour l'utilisateur, un fichier qu'il a fermé réapparaît tout seul, et si la macro réserve l'exécution suivante, le phénomène se répète.

Tout classeur qui réserve une exécution doit donc l'annuler à la fermeture :

' Dans ThisWorkbook
Private Sub Workbook_BeforeClose(Cancel As Boolean)
    StopRefresh
End Sub

Si l'utilisateur annule ensuite la fermeture au moment de la demande d'enregistrement, le classeur reste ouvert avec le minuteur arrêté. Si cela compte, relancez-le dans Workbook_Activate. Le guide BeforeClose traite ce cas.

Un Excel occupé, LatestTime, et un planning qui dérive

La règle de la série s'applique ici : Excel n'exécute la réservation que lorsqu'il est disponible. Si l'utilisateur est en train de saisir dans une cellule, a une boîte de dialogue ouverte, ou si une autre macro tourne à 17:00, la macro attend que cela se termine.

Le troisième argument, LatestTime, fixe une limite à cette attente. Si Excel ne peut pas exécuter la macro avant cette heure-là, la réservation est abandonnée :

' Executer a 17:00, ou pas du tout si Excel est encore occupe a 17:05
Application.OnTime runAt, "DailyExport", runAt + TimeSerial(0, 5, 0)

Cette attente explique aussi pourquoi une tâche répétitive dérive. Now + 5 minutes, mesuré à la fin de chaque exécution, ajoute à chaque intervalle la durée de l'exécution et le moindre retard. Si vous voulez des exécutions à :00, :05, :10, calculez plutôt la prochaine réservation à partir de la précédente, et sautez les créneaux déjà passés :

Sub BookNext()
    mNextRun = mNextRun + TimeSerial(0, INTERVAL_MIN, 0)
    Do While mNextRun <= Now                   ' Excel etait occupe : sauter les creneaux manques
        mNextRun = mNextRun + TimeSerial(0, INTERVAL_MIN, 0)
    Loop
    Application.OnTime mNextRun, "RefreshPrices"
End Sub

OnTime travaille à la seconde près, pas plus finement. Pour tout ce qui est plus rapide, ce n'est pas le bon outil ; le guide Timer traite de la mesure des intervalles courts.

Le parti pris : OnTime n'est pas un planificateur

OnTime exécute une macro tant que ce classeur est ouvert dans l'Excel de quelqu'un. C'est le bon outil pour un tableau de bord qui se rafraîchit toutes les quelques minutes, un rappel d'enregistrement, ou un message d'état qui s'efface tout seul. C'est le mauvais outil pour lancer l'export chaque nuit à 2 h : personne n'a Excel ouvert à cette heure-là, un portable en veille rate le rendez-vous, et une seule réinitialisation ou un plantage brise la chaîne sans laisser de trace.

Pour les tâches qui doivent avoir lieu que quelqu'un soit devant l'écran ou non, utilisez le Planificateur de tâches de Windows pour ouvrir le classeur, et laissez Workbook_Open faire le travail, comme l'explique le guide Workbook_Open. Réservez OnTime au minutage à l'intérieur d'une session, et donnez à chaque réservation un moyen d'être annulée.

Comment ExcelMaster aide

Les bugs d'OnTime se manifestent plus tard et ailleurs : un fichier fermé qui se rouvre à midi, un rafraîchissement qui refuse de s'arrêter, un minuteur qui ne se dérègle qu'après qu'on a cliqué sur Réinitialiser.

ExcelMaster lit le code du classeur, retrouve chaque réservation OnTime, vérifie que chacune a une annulation correspondante qui utilise la même heure conservée, et peut ajouter le nettoyage dans Workbook_BeforeClose qui empêche le fichier de se rouvrir tout seul.

Questions fréquentes

Comment exécuter une macro toutes les 5 minutes en VBA Excel ?

Réservez la première exécution avec Application.OnTime Now + TimeSerial(0, 5, 0), "MyMacro", et à la fin de MyMacro, réservez la suivante de la même façon. Conservez chaque heure réservée dans une variable de niveau module pour pouvoir l'annuler.

Comment arrêter Application.OnTime ?

Appelez Application.OnTime avec la même heure et le même nom de procédure que lors de la réservation, plus Schedule:=False. L'heure doit correspondre exactement : utilisez la variable conservée, pas un nouveau calcul à partir de Now.

Pourquoi OnTime renvoie-t-il l'erreur 1004 quand je l'annule ?

Aucune réservation ne correspond à l'heure et au nom de procédure transmis, en général parce que l'heure a été recalculée, ou que la réservation s'est déjà exécutée. Annulez avec l'heure conservée, et entourez l'annulation d'un On Error Resume Next limité à une ligne.

Pourquoi mon classeur se rouvre-t-il tout seul ?

Une réservation faite avec OnTime était encore dans la liste d'Excel au moment de la fermeture du classeur : Excel a donc rouvert le fichier pour exécuter la macro. Annulez la réservation dans Workbook_BeforeClose.

OnTime fonctionne-t-il si Excel est fermé ?

Non. La réservation n'existe que dans l'Excel en cours d'exécution. Pour lancer une macro quand Excel est fermé, planifiez l'ouverture du classeur avec le Planificateur de tâches de Windows et placez le travail dans Workbook_Open.

Testé dans

Testé dans : Excel 365 (Windows 11), VBA 7.1 — vérifié le 03/10/2026.

Guides connexes : VBA Shortcut Key · VBA SendKeys · VBA Wait · VBA Sleep · VBA Timer · VBA Now · VBA Global Variable · VBA Workbook_BeforeClose