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

VBA OnTime en Excel — ejecutar una macro a una hora o cada N minutos, y conseguir pararla

|

VBA OnTime en Excel — ejecutar una macro a una hora o cada N minutos, y conseguir pararla

TL;DR — Application.OnTime no pone en marcha un temporizador. Hace una reserva en la cola de Excel: a esta hora, ejecuta esta macro. Tu código termina al instante y Excel sigue utilizable; cuando llega la hora y Excel está listo, ejecuta la macro. La reserva se identifica por la hora exacta y el nombre de la macro, así que para cancelarla tienes que volver a pasar las dos cosas, lo que obliga a guardar la hora en una variable de nivel de módulo. Para una tarea repetida, la propia macro reserva su siguiente ejecución. Cancela en Workbook_BeforeClose, porque cerrar el libro no cancela nada: Excel volverá a abrir el archivo para cumplir la cita.

Private mNextRun As Date                       ' la reserva que quizas tengas que cancelar

Sub StartRefresh()
    mNextRun = Now + TimeSerial(0, 5, 0)       ' dentro de cinco minutos
    Application.OnTime mNextRun, "RefreshPrices"
End Sub

Sub StopRefresh()
    On Error Resume Next                       ' error 1004 si no hay nada reservado
    Application.OnTime mNextRun, "RefreshPrices", Schedule:=False
    On Error GoTo 0
End Sub

Este es el segundo artículo de una serie sobre macros que Excel ejecuta por ti. La guía de atajos de teclado trata las macros que se lanzan desde el teclado, y la guía de SendKeys las pulsaciones simuladas. La idea que las une: ninguna llama a tu macro directamente. Cada una deja una petición en la cola de Excel, y Excel la ejecuta cuando está libre y listo. Con OnTime, la petición lleva una hora pegada, y se queda en la cola hasta que se ejecuta o hasta que la retiras con exactamente los mismos datos.

Lo que aprenderás

  • El modelo mental: una reserva, no un temporizador en marcha
  • Ejecutar una macro a una hora del día, y cada N minutos
  • Por qué falla la cancelación, y la variable que lo arregla
  • El temporizador que ya no puedes parar tras un restablecimiento del código
  • Por qué cerrar el libro hace que Excel lo vuelva a abrir
  • Excel ocupado, LatestTime y una programación que se desvía
  • Cuándo OnTime es la herramienta equivocada

El modelo mental: una reserva, no un temporizador

Compara OnTime con un bucle que espera:

' Bloquea Excel: no puede pasar nada mas durante cinco minutos
Application.Wait Now + TimeSerial(0, 5, 0)
RefreshPrices

' Hace una reserva y vuelve al instante: Excel sigue utilizable
Application.OnTime Now + TimeSerial(0, 5, 0), "RefreshPrices"

Application.Wait y Sleep mantienen tu macro en marcha y Excel congelado. OnTime le pasa una nota a Excel y termina. Entre ahora y la reserva no se está ejecutando ningún código VBA; el usuario trabaja con normalidad.

Excel lleva una lista de estas reservas. Cada entrada tiene dos claves, una fecha y hora y un nombre de procedimiento, y Excel encuentra una entrada haciendo coincidir las dos. Todo lo demás de este artículo sale de ahí: puedes reservar varias, cancelas una nombrándola con exactitud, y la lista pertenece a Excel, no a tu libro.

Ejecutar una macro a una hora del día

Dale a OnTime una fecha y una hora completas, para que no haya duda sobre qué día quieres decir:

Sub BookDailyExport()
    Dim runAt As Date
    runAt = Date + TimeSerial(17, 0, 0)        ' hoy a las 17:00
    If runAt <= Now Then runAt = runAt + 1     ' ya ha pasado: manana a las 17:00
    Application.OnTime runAt, "DailyExport"
End Sub

Muchos ejemplos pasan solo TimeValue("17:00:00"). Construir tú la fecha deja la regla a la vista en el código: si la hora ya ha pasado, la próxima ejecución es mañana, no ahora. La guía de Now explica por qué Date más una hora da un valor real de fecha y hora, y TimeSerial mantiene los cálculos a salvo de problemas de configuración regional.

Ejecutar una macro cada N minutos

No hay opción de repetición. Una tarea repetida es una macro que reserva su propia siguiente ejecución al final:

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
    ' ... el trabajo de verdad ...
    StartRefresh                               ' reserva la siguiente ejecucion
End Sub

StartRefresh arranca la cadena y RefreshPrices la mantiene viva. Para detener la cadena tienes que eliminar la única reserva que está hecha en ese momento, y ahí es donde falla casi todo el código con OnTime.

Cancelar: la hora exacta, o el error 1004

Para cancelar, vuelve a llamar a OnTime con Schedule:=False. Excel busca entonces una entrada con la misma hora y el mismo nombre de procedimiento. Esto parece correcto y no funciona:

' Mal: Now ya ha avanzado, asi que esta hora no coincide con ninguna reserva
Application.OnTime Now + TimeSerial(0, 5, 0), "RefreshPrices", Schedule:=False

No hay ninguna reserva a esa hora nueva, así que Excel lanza el Run-time error 1004: Method 'OnTime' of object '_Application' failed (en español: Error 1004 en tiempo de ejecución: Error en el método 'OnTime' de objeto '_Application'), y la reserva real sigue en pie. Por eso la hora vive en una variable de nivel de módulo (mNextRun arriba). Reserva con ella, cancela con ella, y los datos siempre coinciden.

El On Error Resume Next de StopRefresh es deliberado y cubre una sola línea: si no hay nada reservado, por ejemplo porque la macro ya se ejecutó, la cancelación lanza el 1004 y no hay nada que hacer al respecto. La guía de On Error explica por qué conviene que un controlador así sea tan estrecho.

El temporizador que ya no puedes parar

La variable tiene un punto débil. Las variables de nivel de módulo se borran cada vez que el proyecto de VBA se restablece: cuando pulsas el botón Restablecer, cuando un error no controlado termina el código, cuando el código ejecuta End o cuando editas código mientras está en pausa. La guía de variables globales los enumera todos.

Tras un restablecimiento, mNextRun vale 0. La reserva sigue en la lista de Excel, pero tu código ya no conoce su hora, así que StopRefresh no cancela nada. La macro sigue ejecutándose cada cinco minutos y se vuelve a reservar cada vez.

Guarda una copia de la hora en algún sitio que sobreviva a un restablecimiento, como una celda de una hoja de configuración oculta:

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 aun así se te escapa un temporizador desbocado mientras desarrollas, cerrar Excel por completo vacía la lista.

Cerrar el libro no cancela nada

La reserva pertenece a Excel, no al libro. Si el usuario cierra tu libro y Excel sigue abierto, a la hora reservada Excel vuelve a abrir el libro para ejecutar la macro. Para el usuario, un archivo que había cerrado reaparece solo, y si la macro reserva la siguiente ejecución, sigue pasando.

Así que todo libro que reserva una ejecución debe cancelarla al cerrarse:

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

Si después el usuario cancela el cierre en el aviso de guardar, el libro sigue abierto con el temporizador parado. Si eso importa, vuelve a arrancarlo en Workbook_Activate. La guía de BeforeClose trata ese caso.

Excel ocupado, LatestTime y una programación que se desvía

Aquí se aplica la regla de la serie: Excel solo ejecuta la reserva cuando está listo. Si a las 17:00 el usuario está escribiendo en una celda, tiene un cuadro de diálogo abierto o se está ejecutando otra macro, la macro espera hasta que eso termine.

El tercer argumento, LatestTime, pone un límite a esa espera. Si Excel no puede ejecutar la macro antes de esa hora, la reserva se descarta:

' Ejecutar a las 17:00, o no ejecutar si Excel sigue ocupado a las 17:05
Application.OnTime runAt, "DailyExport", runAt + TimeSerial(0, 5, 0)

La espera también explica por qué se desvía una tarea repetida. Now + 5 minutos, medido al final de cada ejecución, suma a cada intervalo lo que dura la ejecución y cualquier retraso. Si quieres ejecuciones a las :00, :05, :10, reserva la siguiente a partir de la reserva anterior, y sáltate las horas que ya han pasado:

Sub BookNext()
    mNextRun = mNextRun + TimeSerial(0, INTERVAL_MIN, 0)
    Do While mNextRun <= Now                   ' Excel estaba ocupado: saltar las horas perdidas
        mNextRun = mNextRun + TimeSerial(0, INTERVAL_MIN, 0)
    Loop
    Application.OnTime mNextRun, "RefreshPrices"
End Sub

OnTime trabaja al segundo, no con más precisión. Para algo más rápido es la herramienta equivocada; la guía de Timer trata cómo medir intervalos cortos.

La decisión de criterio: OnTime no es un programador de tareas

OnTime ejecuta una macro mientras este libro está abierto en el Excel de alguien. Es la herramienta adecuada para un panel que se actualiza cada pocos minutos, un recordatorio de guardar o un mensaje de estado que se borra solo. Es la herramienta equivocada para ejecutar la exportación cada noche a las 2 de la madrugada: a esa hora no hay ningún Excel abierto, un portátil en suspensión se salta la hora, y un solo restablecimiento o un cuelgue rompe la cadena sin dejar rastro.

Para tareas que tienen que ocurrir haya o no alguien delante del ordenador, usa el Programador de tareas de Windows para abrir el libro y deja que Workbook_Open haga el trabajo, como describe la guía de Workbook_Open. Reserva OnTime para medir el tiempo dentro de una sesión, y dale a cada reserva una forma de cancelarse.

Cómo ayuda ExcelMaster

Los fallos de OnTime aparecen más tarde y en otro sitio: un archivo cerrado que se vuelve a abrir a mediodía, una actualización que no hay manera de parar, un temporizador que solo se porta mal después de que alguien pulsara Restablecer.

ExcelMaster lee el código del libro, encuentra cada reserva de OnTime, comprueba que cada una tenga su cancelación correspondiente con la misma hora guardada y puede añadir la limpieza en Workbook_BeforeClose que evita que el archivo se vuelva a abrir solo.

Preguntas frecuentes

¿Cómo ejecuto una macro cada 5 minutos en Excel VBA?

Reserva la primera ejecución con Application.OnTime Now + TimeSerial(0, 5, 0), "MyMacro", y al final de MyMacro reserva la siguiente de la misma forma. Guarda cada hora reservada en una variable de nivel de módulo para poder cancelarla.

¿Cómo detengo Application.OnTime?

Llama a Application.OnTime con la misma hora y el mismo nombre de procedimiento que reservaste, y con Schedule:=False. La hora tiene que coincidir exactamente, así que usa la variable guardada, no un nuevo cálculo con Now.

¿Por qué OnTime da el error 1004 al cancelarlo?

Ninguna reserva coincide con la hora y el nombre de procedimiento que pasaste, normalmente porque la hora se volvió a calcular o porque la reserva ya se ejecutó. Cancela con la hora guardada y envuelve la cancelación en un On Error Resume Next de una sola línea.

¿Por qué mi libro se vuelve a abrir solo?

Una reserva hecha con OnTime seguía en la lista de Excel cuando se cerró el libro, así que Excel volvió a abrir el archivo para ejecutar la macro. Cancela la reserva en Workbook_BeforeClose.

¿OnTime se ejecuta si Excel está cerrado?

No. La reserva solo existe en el Excel en ejecución. Para ejecutar una macro con Excel cerrado, programa el libro con el Programador de tareas de Windows y pon el trabajo en Workbook_Open.

Probado en

Probado en: Excel 365 (Windows 11), VBA 7.1 — última verificación el 03/10/2026.

Guías relacionadas: VBA Shortcut Key · VBA SendKeys · VBA Wait · VBA Sleep · VBA Timer · VBA Now · VBA Global Variable · VBA Workbook_BeforeClose