Ubuntu – How to use cron to schedule a script that implements daylight saving on a non- DST aware application when the server automatically uses DST

8.04cron-jobsservertime

My server (running ubuntu 8.04LTS server) reports the time as 9:38PM BST right now. BST (British Summer Time) is 1 hour ahead of UTC (or Greenwich Mean Time if you really want to confuse matters)

The act of parliament defines that we in the UK use BST for

the period beginning at one o'clock,
Greenwich mean time, in the morning of
the last Sunday in March and ending at
one o'clock, Greenwich mean time, in
the morning of the last Sunday in
October.

No problems scheduling this in cron but I don't know what date format/timezone I should be using. Do I set it to move forward at 1AM but back at 2AM when it ends? That makes sense if the machine uses BST but then I worry that that cron will not trigger at 2AM because the system clock might get reset back to 1AM before it has a chance to trigger – thus making my script run 1 hour late.

Or does it just use UTC?

Best Answer

The answer lies in the cron sources (which you can get by apt-get source cron), particularly in the main loop at lines 159--272 of file cron.c.

crond sleeps for a minute, then wakes up and queries the system time, comparing it to its own idea of time (i.e., what time it would be if nothing altered the clock). Based on the difference between the actual and the expected time, crond takes different actions; two of them are relevant in your case:

  1. Time has leaped forward more than 5 minutes but less than 3 hours (DST starts): cron runs wildcard jobs scheduled at the actual time, and any job scheduled at a fixed time between the computed time and the actual time. Relevant source is at lines 221--247:

      /*
       * case 2: timeDiff is a medium-sized positive number,
       * for example because we went to DST run wildcard
       * jobs once, then run any fixed-time jobs that would
       * otherwise be skipped if we use up our minute
       * (possible, if there are a lot of jobs to run) go
       * around the loop again so that wildcard jobs have
       * a chance to run, and we do our housekeeping
       */
      Debug(DSCH, ("[%d], DST begins %d minutes to go\n",
          getpid(), timeRunning - virtualTime))
      /* run wildcard jobs for current minute */
      find_jobs(timeRunning, &database, TRUE, FALSE);
    
    
      /* run fixed-time jobs for each minute missed */ 
      do {
         if (job_runqueue())
                 sleep(10);
         virtualTime++;
         find_jobs(virtualTime, &database, FALSE, TRUE);
         set_time();
      } while (virtualTime< timeRunning &&
          clockTime == timeRunning);
      break;
    
  2. Time has gone backwards less than 3 hours (DST ends): just run wildcard jobs, skip fixed-schedule jobs since they have already run. Relevant source is at lines 247--258:

    /*
     * case 3: timeDiff is a small or medium-sized
     * negative num, eg. because of DST ending just run
     * the wildcard jobs. The fixed-time jobs probably
     * have already run, and should not be repeated
     * virtual time does not change until we are caught up
     */
    Debug(DSCH, ("[%d], DST ends %d minutes to go\n",
        getpid(), virtualTime - timeRunning))
    find_jobs(timeRunning, &database, TRUE, FALSE);
    break;
    

So, when entering DST, you should have no problem: your script will be run (either just before, or immediately after the time leap).

When exiting DST, there is a risk that your (fixed-time) job will be skipped, if you schedule it exactly at 1 o'clock. My suggestion would be to schedule the run either 1 minute before 1 o'clock, or at 2 o'clock (or after).