Regenerate.
[bpt/emacs.git] / lisp / calendar / cal-dst.el
CommitLineData
e716fd62 1;;; cal-dst.el --- calendar functions for daylight saving rules
3e03d7c7 2
a20b3848 3;; Copyright (C) 1993, 1994, 1995, 1996, 2001, 2002, 2003, 2004, 2005,
f0fa15c5 4;; 2006, 2007 Free Software Foundation, Inc.
3e03d7c7
JB
5
6;; Author: Paul Eggert <eggert@twinsun.com>
7;; Edward M. Reingold <reingold@cs.uiuc.edu>
dbfca9c4 8;; Maintainer: Glenn Morris <rgm@gnu.org>
3e03d7c7 9;; Keywords: calendar
e716fd62 10;; Human-Keywords: daylight saving time, calendar, diary, holidays
3e03d7c7
JB
11
12;; This file is part of GNU Emacs.
13
59243403
RS
14;; GNU Emacs is free software; you can redistribute it and/or modify
15;; it under the terms of the GNU General Public License as published by
16;; the Free Software Foundation; either version 2, or (at your option)
17;; any later version.
18
3e03d7c7 19;; GNU Emacs is distributed in the hope that it will be useful,
59243403
RS
20;; but WITHOUT ANY WARRANTY; without even the implied warranty of
21;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22;; GNU General Public License for more details.
23
24;; You should have received a copy of the GNU General Public License
b578f267 25;; along with GNU Emacs; see the file COPYING. If not, write to the
3a35cf56
LK
26;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
27;; Boston, MA 02110-1301, USA.
3e03d7c7
JB
28
29;;; Commentary:
30
31;; This collection of functions implements the features of calendar.el and
e716fd62 32;; holiday.el that deal with daylight saving time.
3e03d7c7
JB
33
34;; Comments, corrections, and improvements should be sent to
35;; Edward M. Reingold Department of Computer Science
36;; (217) 333-6733 University of Illinois at Urbana-Champaign
37;; reingold@cs.uiuc.edu 1304 West Springfield Avenue
38;; Urbana, Illinois 61801
39
40;;; Code:
41
42(require 'calendar)
12154b44 43(require 'cal-persia)
3e03d7c7 44
cd72c399
GM
45(defcustom calendar-dst-check-each-year-flag t
46 "Non-nil means to check each year for DST transitions as needed.
f3f4e600 47Otherwise assume the next two transitions found after the
cd72c399 48current date apply to all years. This is faster, but not always
e716fd62 49correct, since the dates of daylight saving transitions sometimes
cd72c399
GM
50change."
51 :type 'boolean
52 :version "22.1"
53 :group 'calendar)
54
3e03d7c7 55(defvar calendar-current-time-zone-cache nil
ed589f9a
RS
56 "Cache for result of `calendar-current-time-zone'.")
57(put 'calendar-current-time-zone-cache 'risky-local-variable t)
3e03d7c7
JB
58
59(defvar calendar-system-time-basis
60 (calendar-absolute-from-gregorian '(1 1 1970))
61 "Absolute date of starting date of system clock.")
62
3e03d7c7
JB
63(defun calendar-absolute-from-time (x utc-diff)
64 "Absolute local date of time X; local time is UTC-DIFF seconds from UTC.
65
66X is (HIGH . LOW) or (HIGH LOW . IGNORED) where HIGH and LOW are the
67high and low 16 bits, respectively, of the number of seconds since
681970-01-01 00:00:00 UTC, ignoring leap seconds.
69
70Returns the pair (ABS-DATE . SECONDS) where SECONDS after local midnight on
71absolute date ABS-DATE is the equivalent moment to X."
72 (let* ((h (car x))
73 (xtail (cdr x))
74 (l (+ utc-diff (if (numberp xtail) xtail (car xtail))))
4cc1b78a 75 (u (+ (* 512 (mod h 675)) (floor l 128))))
3e03d7c7
JB
76 ;; Overflow is a terrible thing!
77 (cons (+ calendar-system-time-basis
78 ;; floor((2^16 h +l) / (60*60*24))
6bc457fe 79 (* 512 (floor h 675)) (floor u 675))
3ac14ca0
RS
80 ;; (2^16 h +l) mod (60*60*24)
81 (+ (* (mod u 675) 128) (mod l 128)))))
3e03d7c7
JB
82
83(defun calendar-time-from-absolute (abs-date s)
84 "Time of absolute date ABS-DATE, S seconds after midnight.
85
ec9b5635 86Returns the list (HIGH LOW) where HIGH and LOW are the high and low
3e03d7c7
JB
8716 bits, respectively, of the number of seconds 1970-01-01 00:00:00 UTC,
88ignoring leap seconds, that is the equivalent moment to S seconds after
89midnight UTC on absolute date ABS-DATE."
90 (let* ((a (- abs-date calendar-system-time-basis))
4cc1b78a 91 (u (+ (* 163 (mod a 512)) (floor s 128))))
3e03d7c7 92 ;; Overflow is a terrible thing!
ec9b5635 93 (list
3ac14ca0 94 ;; floor((60*60*24*a + s) / 2^16)
4cc1b78a 95 (+ a (* 163 (floor a 512)) (floor u 512))
3ac14ca0 96 ;; (60*60*24*a + s) mod 2^16
4cc1b78a 97 (+ (* 128 (mod u 512)) (mod s 128)))))
3e03d7c7
JB
98
99(defun calendar-next-time-zone-transition (time)
100 "Return the time of the next time zone transition after TIME.
101Both TIME and the result are acceptable arguments to current-time-zone.
102Return nil if no such transition can be found."
103 (let* ((base 65536);; 2^16 = base of current-time output
104 (quarter-multiple 120);; approx = (seconds per quarter year) / base
105 (time-zone (current-time-zone time))
106 (time-utc-diff (car time-zone))
107 hi
108 hi-zone
109 (hi-utc-diff time-utc-diff)
110 (quarters '(2 1 3)))
111 ;; Heuristic: probe the time zone offset in the next three calendar
112 ;; quarters, looking for a time zone offset different from TIME.
113 (while (and quarters (eq time-utc-diff hi-utc-diff))
114 (setq hi (cons (+ (car time) (* (car quarters) quarter-multiple)) 0))
115 (setq hi-zone (current-time-zone hi))
116 (setq hi-utc-diff (car hi-zone))
117 (setq quarters (cdr quarters)))
118 (and
119 time-utc-diff
120 hi-utc-diff
121 (not (eq time-utc-diff hi-utc-diff))
122 ;; Now HI is after the next time zone transition.
123 ;; Set LO to TIME, and then binary search to increase LO and decrease HI
124 ;; until LO is just before and HI is just after the time zone transition.
125 (let* ((tail (cdr time))
126 (lo (cons (car time) (if (numberp tail) tail (car tail))))
127 probe)
128 (while
129 ;; Set PROBE to halfway between LO and HI, rounding down.
130 ;; If PROBE equals LO, we are done.
131 (let* ((lsum (+ (cdr lo) (cdr hi)))
132 (hsum (+ (car lo) (car hi) (/ lsum base)))
133 (hsumodd (logand 1 hsum)))
134 (setq probe (cons (/ (- hsum hsumodd) 2)
135 (/ (+ (* hsumodd base) (% lsum base)) 2)))
136 (not (equal lo probe)))
137 ;; Set either LO or HI to PROBE, depending on probe results.
138 (if (eq (car (current-time-zone probe)) hi-utc-diff)
139 (setq hi probe)
140 (setq lo probe)))
141 hi))))
142
143(defun calendar-time-zone-daylight-rules (abs-date utc-diff)
144 "Return daylight transition rule for ABS-DATE, UTC-DIFF sec offset from UTC.
e716fd62
CY
145ABS-DATE must specify a day that contains a daylight saving transition.
146The result has the proper form for `calendar-daylight-savings-starts'."
3e03d7c7
JB
147 (let* ((date (calendar-gregorian-from-absolute abs-date))
148 (weekday (% abs-date 7))
149 (m (extract-calendar-month date))
150 (d (extract-calendar-day date))
151 (y (extract-calendar-year date))
152 (last (calendar-last-day-of-month m y))
153 (candidate-rules
154 (append
155 ;; Day D of month M.
156 (list (list 'list m d 'year))
157 ;; The first WEEKDAY of month M.
158 (if (< d 8)
159 (list (list 'calendar-nth-named-day 1 weekday m 'year)))
160 ;; The last WEEKDAY of month M.
161 (if (> d (- last 7))
162 (list (list 'calendar-nth-named-day -1 weekday m 'year)))
163 ;; The first WEEKDAY after day J of month M, for D-6 < J <= D.
164 (let (l)
165 (calendar-for-loop j from (max 2 (- d 6)) to (min d (- last 8)) do
166 (setq l
167 (cons
168 (list 'calendar-nth-named-day 1 weekday m 'year j)
169 l)))
12154b44
PE
170 l)
171 ;; 01-01 and 07-01 for this year's Persian calendar.
172 (if (and (= m 3) (<= 20 d) (<= d 21))
173 '((calendar-gregorian-from-absolute
174 (calendar-absolute-from-persian
175 (list 1 1 (- year 621))))))
176 (if (and (= m 9) (<= 22 d) (<= d 23))
177 '((calendar-gregorian-from-absolute
178 (calendar-absolute-from-persian
179 (list 7 1 (- year 621))))))))
3e03d7c7 180 (prevday-sec (- -1 utc-diff)) ;; last sec of previous local day
6bc457fe
PE
181 (year (1+ y)))
182 ;; Scan through the next few years until only one rule remains.
183 (while
184 (let ((rules candidate-rules)
185 new-rules)
186 (while
187 (let*
188 ((rule (car rules))
189 (date
190 ;; The following is much faster than
191 ;; (calendar-absolute-from-gregorian (eval rule)).
192 (cond ((eq (car rule) 'calendar-nth-named-day)
193 (eval (cons 'calendar-nth-named-absday (cdr rule))))
194 ((eq (car rule) 'calendar-gregorian-from-absolute)
195 (eval (car (cdr rule))))
196 (t (let ((g (eval rule)))
197 (calendar-absolute-from-gregorian g))))))
198 (or (equal
199 (current-time-zone
200 (calendar-time-from-absolute date prevday-sec))
201 (current-time-zone
202 (calendar-time-from-absolute (1+ date) prevday-sec)))
203 (setq new-rules (cons rule new-rules)))
204 (setq rules (cdr rules))))
205 ;; If no rules remain, just use the first candidate rule;
206 ;; it's wrong in general, but it's right for at least one year.
207 (setq candidate-rules (if new-rules (nreverse new-rules)
208 (list (car candidate-rules))))
209 (setq year (1+ year))
210 (cdr candidate-rules)))
211 (car candidate-rules)))
3e03d7c7 212
cd72c399
GM
213;; TODO it might be better to extract this information directly from
214;; the system timezone database. But cross-platform...?
215;; See thread
216;; http://lists.gnu.org/archive/html/emacs-pretest-bug/2006-11/msg00060.html
217(defun calendar-dst-find-data (&optional time)
e716fd62 218 "Find data on the first daylight saving time transitions after TIME.
cd72c399
GM
219TIME defaults to `current-time'. Return value is as described
220for `calendar-current-time-zone'."
221 (let* ((t0 (or time (current-time)))
222 (t0-zone (current-time-zone t0))
223 (t0-utc-diff (car t0-zone))
224 (t0-name (car (cdr t0-zone))))
225 (if (not t0-utc-diff)
226 ;; Little or no time zone information is available.
227 (list nil nil t0-name t0-name nil nil nil nil)
228 (let* ((t1 (calendar-next-time-zone-transition t0))
229 (t2 (and t1 (calendar-next-time-zone-transition t1))))
230 (if (not t2)
e716fd62 231 ;; This locale does not have daylight saving time.
cd72c399 232 (list (/ t0-utc-diff 60) 0 t0-name t0-name nil nil 0 0)
e716fd62 233 ;; Use heuristics to find daylight saving parameters.
cd72c399
GM
234 (let* ((t1-zone (current-time-zone t1))
235 (t1-utc-diff (car t1-zone))
236 (t1-name (car (cdr t1-zone)))
237 (t1-date-sec (calendar-absolute-from-time t1 t0-utc-diff))
238 (t2-date-sec (calendar-absolute-from-time t2 t1-utc-diff))
239 ;; TODO When calendar-dst-check-each-year-flag is non-nil,
240 ;; the rules can be simpler than they currently are.
241 (t1-rules (calendar-time-zone-daylight-rules
242 (car t1-date-sec) t0-utc-diff))
243 (t2-rules (calendar-time-zone-daylight-rules
244 (car t2-date-sec) t1-utc-diff))
245 (t1-time (/ (cdr t1-date-sec) 60))
246 (t2-time (/ (cdr t2-date-sec) 60)))
247 (cons
248 (/ (min t0-utc-diff t1-utc-diff) 60)
249 (cons
250 (/ (abs (- t0-utc-diff t1-utc-diff)) 60)
251 (if (< t0-utc-diff t1-utc-diff)
252 (list t0-name t1-name t1-rules t2-rules t1-time t2-time)
253 (list t1-name t0-name t2-rules t1-rules t2-time t1-time)
254 )))))))))
255
256(defvar calendar-dst-transition-cache nil
e716fd62 257 "Internal cal-dst variable storing date of daylight saving time transitions.
cd72c399
GM
258Value is a list with elements of the form (YEAR START END), where
259START and END are expressions that when evaluated return the
260start and end dates (respectively) for DST in YEAR. Used by the
261function `calendar-dst-find-startend'.")
262
263(defun calendar-dst-find-startend (year)
e716fd62 264 "Find the dates in YEAR on which daylight saving time starts and ends.
cd72c399
GM
265Returns a list (YEAR START END), where START and END are
266expressions that when evaluated return the start and end dates,
267respectively. This function first attempts to use pre-calculated
268data from `calendar-dst-transition-cache', otherwise it calls
269`calendar-dst-find-data' (and adds the results to the cache)."
270 (let ((e (assoc year calendar-dst-transition-cache))
271 f)
272 (or e
273 (progn
274 (setq e (calendar-dst-find-data (encode-time 1 0 0 1 1 year))
275 f (nth 4 e)
276 e (list year f (nth 5 e))
277 calendar-dst-transition-cache
278 (append calendar-dst-transition-cache (list e)))
279 e))))
280
3e03d7c7
JB
281(defun calendar-current-time-zone ()
282 "Return UTC difference, dst offset, names and rules for current time zone.
283
6bc457fe
PE
284Returns (UTC-DIFF DST-OFFSET STD-ZONE DST-ZONE DST-STARTS DST-ENDS
285DST-STARTS-TIME DST-ENDS-TIME), based on a heuristic probing of what the
286system knows:
3e03d7c7
JB
287
288UTC-DIFF is an integer specifying the number of minutes difference between
289 standard time in the current time zone and Coordinated Universal Time
290 (Greenwich Mean Time). A negative value means west of Greenwich.
e716fd62 291DST-OFFSET is an integer giving the daylight saving time offset in minutes.
3e03d7c7
JB
292STD-ZONE is a string giving the name of the time zone when no seasonal time
293 adjustment is in effect.
294DST-ZONE is a string giving the name of the time zone when there is a seasonal
295 time adjustment in effect.
296DST-STARTS and DST-ENDS are sexps in the variable `year' giving the daylight
e716fd62 297 saving time start and end rules, in the form expected by
3e03d7c7 298 `calendar-daylight-savings-starts'.
6bc457fe 299DST-STARTS-TIME and DST-ENDS-TIME are integers giving the number of minutes
e716fd62 300 after midnight that daylight saving time starts and ends.
3e03d7c7 301
6bc457fe
PE
302If the local area does not use a seasonal time adjustment, STD-ZONE and
303DST-ZONE are equal, and all the DST-* integer variables are 0.
3e03d7c7
JB
304
305Some operating systems cannot provide all this information to Emacs; in this
306case, `calendar-current-time-zone' returns a list containing nil for the data
307it can't find."
cd72c399
GM
308 (unless calendar-current-time-zone-cache
309 (setq calendar-current-time-zone-cache (calendar-dst-find-data))))
3e03d7c7 310
e716fd62 311;;; The following eight defvars relating to daylight saving time should NOT be
3e03d7c7
JB
312;;; marked to go into loaddefs.el where they would be evaluated when Emacs is
313;;; dumped. These variables' appropriate values depend on the conditions under
314;;; which the code is INVOKED; so it's inappropriate to initialize them when
315;;; Emacs is dumped---they should be initialized when calendar.el is loaded.
6bc457fe 316;;; They default to US Eastern time if time zone info is not available.
3e03d7c7
JB
317
318(calendar-current-time-zone)
319
6bc457fe 320(defvar calendar-time-zone (or (car calendar-current-time-zone-cache) -300)
3e03d7c7
JB
321 "*Number of minutes difference between local standard time at
322`calendar-location-name' and Coordinated Universal (Greenwich) Time. For
323example, -300 for New York City, -480 for Los Angeles.")
324
325(defvar calendar-daylight-time-offset
6bc457fe 326 (or (car (cdr calendar-current-time-zone-cache)) 60)
e716fd62 327 "*Number of minutes difference between daylight saving and standard time.
a1506d29 328
e716fd62 329If the locale never uses daylight saving time, set this to 0.")
3e03d7c7
JB
330
331(defvar calendar-standard-time-zone-name
6bc457fe 332 (or (car (nthcdr 2 calendar-current-time-zone-cache)) "EST")
3e03d7c7
JB
333 "*Abbreviated name of standard time zone at `calendar-location-name'.
334For example, \"EST\" in New York City, \"PST\" for Los Angeles.")
335
336(defvar calendar-daylight-time-zone-name
6bc457fe 337 (or (car (nthcdr 3 calendar-current-time-zone-cache)) "EDT")
e716fd62 338 "*Abbreviated name of daylight saving time zone at `calendar-location-name'.
3e03d7c7 339For example, \"EDT\" in New York City, \"PDT\" for Los Angeles.")
a1506d29 340
cd72c399
GM
341
342(defun calendar-dst-starts (year)
e716fd62 343 "Return the date of YEAR on which daylight saving time starts.
cd72c399
GM
344This function respects the value of `calendar-dst-check-each-year-flag'."
345 (or (let ((expr (if calendar-dst-check-each-year-flag
346 (cadr (calendar-dst-find-startend year))
347 (nth 4 calendar-current-time-zone-cache))))
348 (if expr (eval expr)))
a9621aa9 349 ;; New US rules commencing 2007. ftp://elsie.nci.nih.gov/pub/.
cd72c399 350 (and (not (zerop calendar-daylight-time-offset))
ed589f9a 351 (calendar-nth-named-day 2 0 3 year))))
cd72c399
GM
352
353(defun calendar-dst-ends (year)
e716fd62 354 "Return the date of YEAR on which daylight saving time ends.
cd72c399
GM
355This function respects the value of `calendar-dst-check-each-year-flag'."
356 (or (let ((expr (if calendar-dst-check-each-year-flag
357 (nth 2 (calendar-dst-find-startend year))
358 (nth 5 calendar-current-time-zone-cache))))
359 (if expr (eval expr)))
a9621aa9 360 ;; New US rules commencing 2007. ftp://elsie.nci.nih.gov/pub/.
cd72c399 361 (and (not (zerop calendar-daylight-time-offset))
ed589f9a 362 (calendar-nth-named-day 1 0 11 year))))
cd72c399
GM
363
364
cd2d091a
RS
365;;;###autoload
366(put 'calendar-daylight-savings-starts 'risky-local-variable t)
3e03d7c7 367(defvar calendar-daylight-savings-starts
cd72c399 368 '(calendar-dst-starts year)
e716fd62 369 "*Sexp giving the date on which daylight saving time starts.
3e03d7c7 370This is an expression in the variable `year' whose value gives the Gregorian
e716fd62
CY
371date in the form (month day year) on which daylight saving time starts. It is
372used to determine the starting date of daylight saving time for the holiday
3e03d7c7
JB
373list and for correcting times of day in the solar and lunar calculations.
374
e716fd62 375For example, if daylight saving time is mandated to start on October 1,
3e03d7c7
JB
376you would set `calendar-daylight-savings-starts' to
377
378 '(10 1 year)
379
d6fc04a8 380If it starts on the first Sunday in April, you would set it to
3e03d7c7 381
d6fc04a8 382 '(calendar-nth-named-day 1 0 4 year)
3e03d7c7 383
e716fd62 384If the locale never uses daylight saving time, set this to nil.")
3e03d7c7 385
cd2d091a 386;;;###autoload
1e608384 387(put 'calendar-daylight-savings-ends 'risky-local-variable t)
3e03d7c7 388(defvar calendar-daylight-savings-ends
cd72c399 389 '(calendar-dst-ends year)
e716fd62 390 "*Sexp giving the date on which daylight saving time ends.
3e03d7c7 391This is an expression in the variable `year' whose value gives the Gregorian
e716fd62
CY
392date in the form (month day year) on which daylight saving time ends. It is
393used to determine the starting date of daylight saving time for the holiday
3e03d7c7
JB
394list and for correcting times of day in the solar and lunar calculations.
395
e716fd62 396For example, if daylight saving time ends on the last Sunday in October:
3e03d7c7 397
d6fc04a8 398 '(calendar-nth-named-day -1 0 10 year)
3e03d7c7 399
e716fd62 400If the locale never uses daylight saving time, set this to nil.")
a1506d29 401
6bc457fe
PE
402(defvar calendar-daylight-savings-starts-time
403 (or (car (nthcdr 6 calendar-current-time-zone-cache)) 120)
e716fd62 404 "*Number of minutes after midnight that daylight saving time starts.")
a1506d29 405
6bc457fe
PE
406(defvar calendar-daylight-savings-ends-time
407 (or (car (nthcdr 7 calendar-current-time-zone-cache))
408 calendar-daylight-savings-starts-time)
e716fd62 409 "*Number of minutes after midnight that daylight saving time ends.")
3e03d7c7 410
ec230951 411(defun dst-in-effect (date)
e716fd62 412 "True if on absolute DATE daylight saving time is in effect.
021edd45 413Fractional part of DATE is local standard time of day."
ec230951
ER
414 (let* ((year (extract-calendar-year
415 (calendar-gregorian-from-absolute (floor date))))
021edd45
ER
416 (dst-starts-gregorian (eval calendar-daylight-savings-starts))
417 (dst-ends-gregorian (eval calendar-daylight-savings-ends))
418 (dst-starts (and dst-starts-gregorian
ec230951 419 (+ (calendar-absolute-from-gregorian
021edd45 420 dst-starts-gregorian)
ec230951
ER
421 (/ calendar-daylight-savings-starts-time
422 60.0 24.0))))
021edd45 423 (dst-ends (and dst-ends-gregorian
ec230951 424 (+ (calendar-absolute-from-gregorian
021edd45 425 dst-ends-gregorian)
ec230951
ER
426 (/ (- calendar-daylight-savings-ends-time
427 calendar-daylight-time-offset)
428 60.0 24.0)))))
021edd45
ER
429 (and dst-starts dst-ends
430 (if (< dst-starts dst-ends)
431 (and (<= dst-starts date) (< date dst-ends))
432 (or (<= dst-starts date) (< date dst-ends))))))
ec230951
ER
433
434(defun dst-adjust-time (date time &optional style)
435 "Adjust, to account for dst on DATE, decimal fraction standard TIME.
436Returns a list (date adj-time zone) where `date' and `adj-time' are the values
437adjusted for `zone'; here `date' is a list (month day year), `adj-time' is a
438decimal fraction time, and `zone' is a string.
439
440Optional parameter STYLE forces the result time to be standard time when its
e716fd62 441value is 'standard and daylight saving time (if available) when its value is
ec230951
ER
442'daylight.
443
e716fd62 444Conversion to daylight saving time is done according to
ec230951
ER
445`calendar-daylight-savings-starts', `calendar-daylight-savings-ends',
446`calendar-daylight-savings-starts-time',
447`calendar-daylight-savings-ends-time', and
448`calendar-daylight-savings-offset'."
449
450 (let* ((rounded-abs-date (+ (calendar-absolute-from-gregorian date)
451 (/ (round (* 60 time)) 60.0 24.0)))
452 (dst (dst-in-effect rounded-abs-date))
453 (time-zone (if dst
454 calendar-daylight-time-zone-name
455 calendar-standard-time-zone-name))
456 (time (+ rounded-abs-date
457 (if dst (/ calendar-daylight-time-offset 24.0 60.0) 0))))
458 (list (calendar-gregorian-from-absolute (truncate time))
459 (* 24.0 (- time (truncate time)))
460 time-zone)))
461
3e03d7c7
JB
462(provide 'cal-dst)
463
ab5796a9 464;;; arch-tag: a141d204-213c-4ca5-bdc6-f9df3aa92aad
3e03d7c7 465;;; cal-dst.el ends here