How to compute the moment of the next DST change
Dear time experts, I want to write a cron job or similar that activates one week prior to daylight saving time changes. (Or, more generically, one week prior to any time jumps, for any reason, DST or else.) Any pointers? I have looked at the usual places: POSIX time functions, various date/time modules on CPAN, etc. Nothing seems to do that computation. Do I need to parse the tz database myself? Thanks, Simon
Simon Perreault <simon.perreault@viagenie.ca> wrote on Tue, 2 Apr 2013 at 10:58:49 +0200 in <515A9DC9.8020009@viagenie.ca>:
I want to write a cron job or similar that activates one week prior to daylight saving time changes. (Or, more generically, one week prior to any time jumps, for any reason, DST or else.)
In casual interactive usage, I use the following, where 2014 is the subsequent calendar year: $ zdump -c 2014 -v US/Eastern | tail US/Eastern Sun Mar 11 06:59:59 2012 UTC = Sun Mar 11 01:59:59 2012 EST isdst=0 US/Eastern Sun Mar 11 07:00:00 2012 UTC = Sun Mar 11 03:00:00 2012 EDT isdst=1 US/Eastern Sun Nov 4 05:59:59 2012 UTC = Sun Nov 4 01:59:59 2012 EDT isdst=1 US/Eastern Sun Nov 4 06:00:00 2012 UTC = Sun Nov 4 01:00:00 2012 EST isdst=0 US/Eastern Sun Mar 10 06:59:59 2013 UTC = Sun Mar 10 01:59:59 2013 EST isdst=0 US/Eastern Sun Mar 10 07:00:00 2013 UTC = Sun Mar 10 03:00:00 2013 EDT isdst=1 US/Eastern Sun Nov 3 05:59:59 2013 UTC = Sun Nov 3 01:59:59 2013 EDT isdst=1 US/Eastern Sun Nov 3 06:00:00 2013 UTC = Sun Nov 3 01:00:00 2013 EST isdst=0 US/Eastern Mon Jan 18 03:14:07 2038 UTC = Sun Jan 17 22:14:07 2038 EST isdst=0 US/Eastern Tue Jan 19 03:14:07 2038 UTC = Mon Jan 18 22:14:07 2038 EST isdst=0 $ So that is one starting point. --jhawk@mit.edu John Hawkinson
Any pointers?
I have looked at the usual places: POSIX time functions, various date/time modules on CPAN, etc. Nothing seems to do that computation. Do I need to parse the tz database myself?
On 02/04/13 09:58, Simon Perreault wrote:
I want to write a cron job or similar that activates one week prior to daylight saving time changes. (Or, more generically, one week prior to any time jumps, for any reason, DST or else.)
Any pointers?
I have looked at the usual places: POSIX time functions, various date/time modules on CPAN, etc. Nothing seems to do that computation. Do I need to parse the tz database myself?
If you're on Linux: TZ1=$(date +%Z) TZ2=$(date =d 'next week' +%Z) if [ $TZ1 != $TZ2 ]; then echo clocks change next week fi You can also use localtime(3) with the current time and the current time plus 7*24*2600 and compare the tm_hour field. jch
Just in case the abbreviation does not change: TIME1=$(date +%H%M) TIME2=$(date -d week +%H%M) TIME3=$(date +%H%M) if [ $TIME1 != $TIME2 -a $TIME3 != $TIME2 ] then echo clocks change next week fi -- Foreca Ltd Jaakko.Hyvatti@foreca.com Keilaranta 1, FI-02150 Espoo, Finland http://www.foreca.com
On 2013-04-02 10:23, John Haxby wrote:
On 02/04/13 09:58, Simon Perreault wrote:
I want to write a cron job or similar that activates one week prior to daylight saving time changes. (Or, more generically, one week prior to any time jumps, for any reason, DST or else.)
Any pointers?
I have looked at the usual places: POSIX time functions, various date/time modules on CPAN, etc. Nothing seems to do that computation. Do I need to parse the tz database myself?
If you're on Linux:
TZ1=$(date +%Z) TZ2=$(date =d 'next week' +%Z) if [ $TZ1 != $TZ2 ]; then echo clocks change next week fi
That wouldn't work if the abbreviations for normal time and daylight savings time are the same, but that might not be a problem for the original poster. It also only works for the date command from GNU coreutils as the -d option either doesn't exist or does something else on other systems. If using the date command from GNU coreutils, you could use +%z or %:z instead of %Z to get a numeric timezone offset instead of a timezone abbreviation.
You can also use localtime(3) with the current time and the current time plus 7*24*2600 and compare the tm_hour field.
That sounds okay, though better to take the minutes into consideration as well in case you call it at xx:59:59 just as the hour is about to roll over. Of course, the cron job would have to run once a day (or whatever, depending on the precision required) to check for a change and then decide what to do. There is no cron time syntax related to jumps in local time. -- -=( Ian Abbott @ MEV Ltd. E-mail: <abbotti@mev.co.uk> )=- -=( Tel: +44 (0)161 477 1898 FAX: +44 (0)161 718 3587 )=-
At 2013-04-02 02:23, John Haxby wrote:
On 02/04/13 09:58, Simon Perreault wrote:
I want to write a cron job or similar that activates one week prior to daylight saving time changes. (Or, more generically, one week prior to any time jumps, for any reason, DST or else.)
...
You can also use localtime(3) with the current time and the current time plus 7*24*2600 and compare the tm_hour field.
that would be 7*24*3600 (=7*24*60*60) (just because nobody mentioned the phreak-slip in follow-up yet :) ) I like the zdump solution, though, since it only needs to be run when the tz database is updated, not every hour. -- Alan Mintz <Alan_Mintz+TZ_IANA@Earthlink.net>
Simon Perreault <simon.perreault@viagenie.ca> writes:
I want to write a cron job or similar that activates one week prior to daylight saving time changes. (Or, more generically, one week prior to any time jumps, for any reason, DST or else.)
If parsing zdump output is appropriate, that would do the trick. If you care about leap seconds as well, that may or may not be available depending on the system. On Red Hat systems, leap-second-aware zone files are stored in /usr/share/zoneinfo/right. Thanks, PM
The tz file could be parsed itself as is being done in my free Windows product Time Zone Master, and a cron file produced from that. A new file would have to be generated after each release of the tz data files. On 2013-04-02 4:58, Simon Perreault wrote:
Dear time experts,
I want to write a cron job or similar that activates one week prior to daylight saving time changes. (Or, more generically, one week prior to any time jumps, for any reason, DST or else.)
Any pointers?
I have looked at the usual places: POSIX time functions, various date/time modules on CPAN, etc. Nothing seems to do that computation. Do I need to parse the tz database myself?
Thanks, Simon
--
This sounds like something that should be in the Python standard library "datetime" module -- but I don't believe it is. Maybe a good project for an enterprising programmer. paul On Apr 2, 2013, at 4:58 AM, Simon Perreault wrote:
Dear time experts,
I want to write a cron job or similar that activates one week prior to daylight saving time changes. (Or, more generically, one week prior to any time jumps, for any reason, DST or else.)
Any pointers?
I have looked at the usual places: POSIX time functions, various date/time modules on CPAN, etc. Nothing seems to do that computation. Do I need to parse the tz database myself?
Thanks, Simon
Might it be practical to add an option to zdump for CSV output, and document that as a public supported API? Maybe include generation of csv companion files beside the binary zone data as part of the makefile target that builds the zone data files?
That's a possibility, but it may make more sense to have your favorite libraries know how to read tz binary files. After all, on any OS that uses the tzdata information, those files exist. On the other hand, auxiliary outputs like CSV files are less likely to be installed as standard practice. There are likely to be libraries already in existence where this feature could be added. The Python one I mentioned is a good example: I expected to find tzdata support there and was surprised to discover it missing, but it seems like an easy enough enhancement to make and submit to the community. paul On Apr 2, 2013, at 11:32 AM, Bennett Todd wrote: Might it be practical to add an option to zdump for CSV output, and document that as a public supported API? Maybe include generation of csv companion files beside the binary zone data as part of the makefile target that builds the zone data files?
On 2 April 2013 11:43, <Paul_Koning@dell.com> wrote:
That's a possibility, but it may make more sense to have your favorite libraries know how to read tz binary files. After all, on any OS that uses the tzdata information, those files exist. On the other hand, auxiliary outputs like CSV files are less likely to be installed as standard practice
Out of curiosity (and perhaps for the good of the order), is there documentation on the format of tz binary files and, if so, where can it be found? -- Tim Parenti
On Tue, Apr 2, 2013, at 15:36, Tim Parenti wrote:
Out of curiosity (and perhaps for the good of the order), is there documentation on the format of tz binary files and, if so, where can it be found?
It's fully specified in the tzfile.5 manpage - I've also got a mostly independently (of tzcode's tzset) written "timezone file inspector" program that I've been meaning to post on the list one of these days, which may or may not be helpful.
On 2013-04-02 20:42, random832@fastmail.us wrote:
On Tue, Apr 2, 2013, at 15:36, Tim Parenti wrote:
Out of curiosity (and perhaps for the good of the order), is there documentation on the format of tz binary files and, if so, where can it be found?
It's fully specified in the tzfile.5 manpage - I've also got a mostly independently (of tzcode's tzset) written "timezone file inspector" program that I've been meaning to post on the list one of these days, which may or may not be helpful.
The definition in the tzfile.5 manpage isn't written very formally. It's kind of loose. One really needs to grok the TZ C code to get the details of the layout. -- -=( Ian Abbott @ MEV Ltd. E-mail: <abbotti@mev.co.uk> )=- -=( Tel: +44 (0)161 477 1898 FAX: +44 (0)161 718 3587 )=-
This shell command should do the trick: emacs -batch -l cal-dst -eval '(message "%s" (format-time-string "%Y-%m-%d %H:%M:%S %z" (calendar-next-time-zone-transition (current-time))))' If I run that right now in Los Angeles, I get: 2013-11-03 01:00:00 -0800
First I want to say thanks to everyone for your help! In the end I think I will parse the output of zdump. Easy, correct, simple. Just the way I like it. Now this original suggestion warrants a reply: Le 2013-04-02 17:59, Paul Eggert a écrit :
This shell command should do the trick:
emacs -batch -l cal-dst -eval '(message "%s" (format-time-string "%Y-%m-%d %H:%M:%S %z" (calendar-next-time-zone-transition (current-time))))'
Interesting... Looking at the source code of "calendar-next-time-zone-transition", it looks very error prone to me. Am I reading the comments right? It initializes a binary search with the results of a heuristic? I know you know what you're doing, it's just a bit unexpected to this time newbie.
(defun calendar-next-time-zone-transition (time) "Return the time of the next time zone transition after TIME. Both TIME and the result are acceptable arguments to `current-time-zone'. Return nil if no such transition can be found." (let* ((base 65536) ; 2^16 = base of current-time output (quarter-multiple 120) ; approx = (seconds per quarter year) / base (time-zone (current-time-zone time)) (time-utc-diff (car time-zone)) hi hi-zone (hi-utc-diff time-utc-diff) (quarters '(2 1 3))) ;; Heuristic: probe the time zone offset in the next three calendar ;; quarters, looking for a time zone offset different from TIME. (while (and quarters (eq time-utc-diff hi-utc-diff)) (setq hi (cons (+ (car time) (* (car quarters) quarter-multiple)) 0) hi-zone (current-time-zone hi) hi-utc-diff (car hi-zone) quarters (cdr quarters))) (and time-utc-diff hi-utc-diff (not (eq time-utc-diff hi-utc-diff)) ;; Now HI is after the next time zone transition. ;; Set LO to TIME, and then binary search to increase LO and decrease HI ;; until LO is just before and HI is just after the time zone transition. (let* ((tail (cdr time)) (lo (cons (car time) (if (numberp tail) tail (car tail)))) probe) (while ;; Set PROBE to halfway between LO and HI, rounding down. ;; If PROBE equals LO, we are done. (let* ((lsum (+ (cdr lo) (cdr hi))) (hsum (+ (car lo) (car hi) (/ lsum base))) (hsumodd (logand 1 hsum))) (setq probe (cons (/ (- hsum hsumodd) 2) (/ (+ (* hsumodd base) (% lsum base)) 2))) (not (equal lo probe))) ;; Set either LO or HI to PROBE, depending on probe results. (if (eq (car (current-time-zone probe)) hi-utc-diff) (setq hi probe) (setq lo probe))) hi))))
Simon -- DTN made easy, lean, and smart --> http://postellation.viagenie.ca NAT64/DNS64 open-source --> http://ecdysis.viagenie.ca STUN/TURN server --> http://numb.viagenie.ca
On 04/02/2013 12:21 PM, Simon Perreault wrote:
Looking at the source code of "calendar-next-time-zone-transition", it looks very error prone to me. Am I reading the comments right? It initializes a binary search with the results of a heuristic?
Yes. It's a heuristic that should work with all real-world time zone histories (including all time zone histories in the tz database). It won't work in general, though. zdump uses a similar heuristic, if memory serves.
Le 2013-04-03 04:45, Paul Eggert a écrit :
Looking at the source code of "calendar-next-time-zone-transition", it looks very error prone to me. Am I reading the comments right? It initializes a binary search with the results of a heuristic?
Yes. It's a heuristic that should work with all real-world time zone histories (including all time zone histories in the tz database). It won't work in general, though.
Thanks! That's what I expected.
zdump uses a similar heuristic, if memory serves.
I suppose magic doesn't exist after all... Simon -- DTN made easy, lean, and smart --> http://postellation.viagenie.ca NAT64/DNS64 open-source --> http://ecdysis.viagenie.ca STUN/TURN server --> http://numb.viagenie.ca
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 A few months ago, I posted to this list (and posted source code to github https://github.com/Boruch-Baum/zdump-3-) a C function that I think will do what you all want. No heuristics or guessing. For the use case "compute the moment of the next DST change", pass to the function the current time/date as the start period, and a 'safe' date in the future (say one year hence). The second entry in the returned struct will be "moment of the next DST change". On 04/03/2013 01:55 AM, Simon Perreault wrote:
Le 2013-04-03 04:45, Paul Eggert a écrit :
Looking at the source code of "calendar-next-time-zone-transition", it looks very error prone to me. Am I reading the comments right? It initializes a binary search with the results of a heuristic?
Yes. It's a heuristic that should work with all real-world time zone histories (including all time zone histories in the tz database). It won't work in general, though.
Thanks! That's what I expected.
zdump uses a similar heuristic, if memory serves.
I suppose magic doesn't exist after all...
Simon
- -- hkp://keys.gnupg.net CA45 09B5 5351 7C11 A9D1 7286 0036 9E45 1595 8BC0 -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.12 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iQIcBAEBAgAGBQJRXDi0AAoJEDvrUfDmCx9LMOMP/RcT040gz2L/UXH5tFp9NefJ Fwl5LEJ20OgsVNhGRMj/CUVqb6PVpd/hPZ3eMY659Xi0FGx2lHFTynmklGoTDpJH wusvEu21+VABU527SzJwDtjjeBhbeKIdb+tRikNRVYUICsdxhddZiiT+8hbdjFlJ iNq6po9Vdw+Ik5C/Y7BC9nsys5fO49CGS6lWMiTnTOIVa6URCYfhC/Su6bTGBySG ikrTxTCAUxxlskPKSVuNoD2sumy+5R50Lm/vNBM3GnwkTA+wBqqrVG8AzmhVNyp2 MvCEW4Q9S6tNT5gFeFunJkpomhpctPTEDZEI0p3r4UmM2S+eYSE+7ZvKpcCUrepF i5q78YnerR37uq+U0mIdd3U0f0MwyKOR/GJGrnspTcrKYTZlQQiyq5a1D8+gJx15 5lZCHptEtZzV8DYCGot3ypq9I0k4hhmh37qkDFK5dlHVk9Xy1DBuLq8w18CxUFfd 1tUQY4fRnvd2J+vy55uTJbeSODOPmWwhAhY/Lnyt7Vv/X5LWRZ3Z4K08ovy/ECGy X+FJ6xVf++B9BEtcRL3v5U6CB0iF1BEiilzCJbOnDg0O0mQGjqLLVmAn3RREBJVa pA7Q84XHdtrPYeGD69YsXI5HHeJtCQNPXZIZS31FIFjX0iCEnrLpehvg4iqYzkRM ys+JLXNpNBoXFUqS3BbC =ceqW -----END PGP SIGNATURE-----
On Wed, Apr 3, 2013, at 10:12, Boruch Baum wrote:
A few months ago, I posted to this list (and posted source code to github https://github.com/Boruch-Baum/zdump-3-) a C function that I think will do what you all want. No heuristics or guessing.
For the use case "compute the moment of the next DST change", pass to the function the current time/date as the start period, and a 'safe' date in the future (say one year hence). The second entry in the returned struct will be "moment of the next DST change".
So...
int zdump( char *tzname, const time_t start, const time_t end, int* num_entries, void** return_data);
Why isn't return_data a struct zdumpinfo **?
char save_secs; The absolute value of the number of seconds that the \fIutc_offset\fP is at variance from the timezone's "standard time". Thus, this value will be zero if not daylight savings time. This value will be negative if this information not would not be available using the \fBlocaltime_r()\fP function.\
This field seems to actually be an int, contrary to the manpage. This doesn't document the fact that it uses the previous entry (what happens if the first entry returned is in DST?) as "standard time", which will fail if the time zone itself changes at the same time as daylight savings changes.
It was pointed out to me privately that my Elisp code does not work if the current time zone is plain UTC or is any other time zone where no clock changes are planned for the future. Here's a slightly-fancier version that should fix this: emacs -batch -l cal-dst -eval ' (message "%s" (let ((nt (calendar-next-time-zone-transition (current-time)))) (and nt (format-time-string "%Y-%m-%d %T %z" nt)))) '
participants (14)
-
Alan Mintz -
Bennett Todd -
Boruch Baum -
David Patte ₯ -
Ian Abbott -
Jaakko Hyvätti -
John Hawkinson -
John Haxby -
Paul Eggert -
Paul_Koning@Dell.com -
Petr Machata -
random832@fastmail.us -
Simon Perreault -
Tim Parenti