3

I have a timer I want to run every day at 4am. Thus, I put something like this in my configuration.

(defvar my/timer nil)
(unless my/timer 
  (setq my/timer (run-at-time "04:00am" (* 24 60 60) #'my/function)))

This works as expected, except that each time this snippet is evaluated for the first time (e.g., when launching emacs), my/function is executed immediately. In fact, evaluating (run-at-time "04:00am" (* 24 60 60) #'my/function) at any time in the day causes this effect.

Maybe I have a misunderstanding, but isn't it supposed to run only at the specified time ?

4

Unfortunately, you're telling it to run the function at 04:00am today. Unless you evaluated that code between midnight and 4am, that's a target time in the past, and so Emacs runs it ASAP.

The run-at-time code knows this is a bit dumb:

   ;; Handle "11:23pm" and the like.  Interpret it as meaning today
   ;; which admittedly is rather stupid if we have passed that time
   ;; already.  (Though only Emacs hackers hack Emacs at that time.)
   (if (stringp time)
       (progn
         (require 'diary-lib)
         (let ((hhmm (diary-entry-time time))
               (now (decode-time)))
           (if (>= hhmm 0)
               (setq time
                     (encode-time 0 (% hhmm 100) (/ hhmm 100)
                                  (decoded-time-day now)
                                  (decoded-time-month now)
                                  (decoded-time-year now)
                                  (decoded-time-zone now)))))))

You could figure out how many seconds there are between now and 4am, and use that instead; or else something like:

(unless my/timer 
  (let ((24hours (* 24 60 60)))
    (setq my/timer (run-at-time "04:00am" 24hours #'my/function))
    (when (> (timer-until my/timer (current-time)) 0)
      (timer-inc-time my/timer 24hours))))
2
  • Thanks, it solves the issue! Could you just explain, in your last snippet, why the run-at-time in the varlist does not immediately call #'my/function ? On the other hand calling the let-form without the body invoke immediately #'my/function... Mar 20 at 7:58
  • 1
    Timers only have an opportunity to trigger when Emacs isn't busy running code; so in this case we can schedule the timer to run in the past and then inspect and manipulate that scheduled time before it gets used.
    – phils
    Mar 20 at 8:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.