TL;DR —
Application.OnTimene 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 dansWorkbook_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
OnTimen'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
