DateTime and summer time
I’ve been looking for a way of comparing the current time with the times of upcoming cron jobs. It looks as if you can do this using modules from the Perl DateTime project. This fabulous collection of modules lets you represent times and dates in pretty much any way you want (including “the little hand is pointing to the twelve and the big hand is pointing to the nine” using DateTime::Format::Baby) and manipulate them in all sorts of ways. You can declare durations, you can do arithmetical operations on dates and durations to get other dates or durations, you can declare time spans and find out whether other dates are in them. One thing which really impressed me is that you can declare sets of dates or timespans then use set operations (union, complement, intersection) between the sets of dates or timespans.
Anyway, it has a handy module called DateTime::Event::Cron which understands times/dates expressed in crontab format, which sounds perfect.
However, after reading the docs I’ve started worrying about details.
Cron isn’t aware of summer time changes – that is, it doesn’t know about them in advance. Instead it reacts when it spots that the time has changed under it.
man cron says:
Local time changes of less than three hours, such as those caused by
the start or end of Daylight Saving Time, are handled specially. This
only applies to jobs that run at a specific time and jobs that are run
with a granularity greater than one hour. Jobs that run more fre-
quently are scheduled normally.
If time has moved forward, those jobs that would have run in the inter-
val that has been skipped will be run immediately. Conversely, if time
has moved backward, care is taken to avoid running jobs twice.
Time changes of more than 3 hours are considered to be corrections to
the clock or timezone, and the new time is used immediately.
DateTime can cope with summertime clock changes when it’s told to use a particular timezone. However, if you try to specify a date that doesn’t exist in that timezone, such as during the lost hour in spring, DateTime will fall over with a fatal error.
Since cron is quite happy to have jobs scheduled during the missing hour, we won’t be able to simply take all the cron times and shove them into DateTime. We’ll have to filter them first. (Unless I’m just not familiar enough with Perl: is a fatal error a big deal? Could my code easily trap it and carry on?)
The DateTime man page recommends getting round summer time problems by using UTC for all the calculations and using the local time zone just for input and presentation. But this wouldn’t help in our case, as the cron times are effectively expressed in the local time zone to start with and may be invalid, in which case the attempt to convert them to UTC will make DateTime fall over with a fatal error.
I’d rather not have a fatal error every year.
One option is simply to look out for the days on which summer time changes. Wikipedia says that Since 1996 European Summer Time has been observed from the last Sunday in March to the last Sunday in October. One could put special checks for those dates in the code. DateTime makes it easy to represent dates like “the last Sunday in March”.
All this assumes specific use of the local time zone. I’m not yet clear on how using the default “floating” time zone might change things. However I have a suspicion that it’ll just behave as cron does, and be taken by surprise by summer time changes – which would be ideal, except that it’d mean that its predictions about how long it is to go until the next cron job is due to run could be totally wrong a couple of times a year.