aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGlenn Morris2006-11-10 08:54:38 +0000
committerGlenn Morris2006-11-10 08:54:38 +0000
commitcd72c39915f4d43a286f1a193ee950c8c8049c10 (patch)
treeaff1d61ee71fe6e79a79f98e85ddaa9ee02a739f
parent86f46920ffbadd4fc01b3e28aa6ea82bc04184e8 (diff)
downloademacs-cd72c39915f4d43a286f1a193ee950c8c8049c10.tar.gz
emacs-cd72c39915f4d43a286f1a193ee950c8c8049c10.zip
Do not assume DST starts/ends on the same date in every year.
(calendar-dst-check-each-year-flag): New customizable variable. (calendar-dst-find-data): New function, extracted from calendar-current-time-zone. (calendar-current-time-zone): Use calendar-dst-find-data. (calendar-dst-transition-cache): New variable. (calendar-dst-find-startend, calendar-dst-starts) (calendar-dst-ends): New functions. (calendar-daylight-savings-starts) (calendar-daylight-savings-ends): Change value to use calendar-dst-starts, calendar-dst-ends; respectively.
-rw-r--r--lisp/calendar/cal-dst.el146
1 files changed, 104 insertions, 42 deletions
diff --git a/lisp/calendar/cal-dst.el b/lisp/calendar/cal-dst.el
index 62327a99c65..9604a4debbc 100644
--- a/lisp/calendar/cal-dst.el
+++ b/lisp/calendar/cal-dst.el
@@ -42,6 +42,16 @@
42(require 'calendar) 42(require 'calendar)
43(require 'cal-persia) 43(require 'cal-persia)
44 44
45(defcustom calendar-dst-check-each-year-flag t
46 "Non-nil means to check each year for DST transitions as needed.
47nil means to assume the next two transitions found after the
48current date apply to all years. This is faster, but not always
49correct, since the dates of Daylight Saving transitions sometimes
50change."
51 :type 'boolean
52 :version "22.1"
53 :group 'calendar)
54
45(defvar calendar-current-time-zone-cache nil 55(defvar calendar-current-time-zone-cache nil
46 "Cache for result of calendar-current-time-zone.") 56 "Cache for result of calendar-current-time-zone.")
47 57
@@ -199,6 +209,74 @@ The result has the proper form for calendar-daylight-savings-starts'."
199 (cdr candidate-rules))) 209 (cdr candidate-rules)))
200 (car candidate-rules))) 210 (car candidate-rules)))
201 211
212;; TODO it might be better to extract this information directly from
213;; the system timezone database. But cross-platform...?
214;; See thread
215;; http://lists.gnu.org/archive/html/emacs-pretest-bug/2006-11/msg00060.html
216(defun calendar-dst-find-data (&optional time)
217 "Find data on the first Daylight Saving Time transitions after TIME.
218TIME defaults to `current-time'. Return value is as described
219for `calendar-current-time-zone'."
220 (let* ((t0 (or time (current-time)))
221 (t0-zone (current-time-zone t0))
222 (t0-utc-diff (car t0-zone))
223 (t0-name (car (cdr t0-zone))))
224 (if (not t0-utc-diff)
225 ;; Little or no time zone information is available.
226 (list nil nil t0-name t0-name nil nil nil nil)
227 (let* ((t1 (calendar-next-time-zone-transition t0))
228 (t2 (and t1 (calendar-next-time-zone-transition t1))))
229 (if (not t2)
230 ;; This locale does not have daylight savings time.
231 (list (/ t0-utc-diff 60) 0 t0-name t0-name nil nil 0 0)
232 ;; Use heuristics to find daylight savings parameters.
233 (let* ((t1-zone (current-time-zone t1))
234 (t1-utc-diff (car t1-zone))
235 (t1-name (car (cdr t1-zone)))
236 (t1-date-sec (calendar-absolute-from-time t1 t0-utc-diff))
237 (t2-date-sec (calendar-absolute-from-time t2 t1-utc-diff))
238 ;; TODO When calendar-dst-check-each-year-flag is non-nil,
239 ;; the rules can be simpler than they currently are.
240 (t1-rules (calendar-time-zone-daylight-rules
241 (car t1-date-sec) t0-utc-diff))
242 (t2-rules (calendar-time-zone-daylight-rules
243 (car t2-date-sec) t1-utc-diff))
244 (t1-time (/ (cdr t1-date-sec) 60))
245 (t2-time (/ (cdr t2-date-sec) 60)))
246 (cons
247 (/ (min t0-utc-diff t1-utc-diff) 60)
248 (cons
249 (/ (abs (- t0-utc-diff t1-utc-diff)) 60)
250 (if (< t0-utc-diff t1-utc-diff)
251 (list t0-name t1-name t1-rules t2-rules t1-time t2-time)
252 (list t1-name t0-name t2-rules t1-rules t2-time t1-time)
253 )))))))))
254
255(defvar calendar-dst-transition-cache nil
256 "Internal cal-dst variable storing date of Daylight Saving Time transitions.
257Value is a list with elements of the form (YEAR START END), where
258START and END are expressions that when evaluated return the
259start and end dates (respectively) for DST in YEAR. Used by the
260function `calendar-dst-find-startend'.")
261
262(defun calendar-dst-find-startend (year)
263 "Find the dates in YEAR on which Daylight Saving Time starts and ends.
264Returns a list (YEAR START END), where START and END are
265expressions that when evaluated return the start and end dates,
266respectively. This function first attempts to use pre-calculated
267data from `calendar-dst-transition-cache', otherwise it calls
268`calendar-dst-find-data' (and adds the results to the cache)."
269 (let ((e (assoc year calendar-dst-transition-cache))
270 f)
271 (or e
272 (progn
273 (setq e (calendar-dst-find-data (encode-time 1 0 0 1 1 year))
274 f (nth 4 e)
275 e (list year f (nth 5 e))
276 calendar-dst-transition-cache
277 (append calendar-dst-transition-cache (list e)))
278 e))))
279
202(defun calendar-current-time-zone () 280(defun calendar-current-time-zone ()
203 "Return UTC difference, dst offset, names and rules for current time zone. 281 "Return UTC difference, dst offset, names and rules for current time zone.
204 282
@@ -226,42 +304,8 @@ DST-ZONE are equal, and all the DST-* integer variables are 0.
226Some operating systems cannot provide all this information to Emacs; in this 304Some operating systems cannot provide all this information to Emacs; in this
227case, `calendar-current-time-zone' returns a list containing nil for the data 305case, `calendar-current-time-zone' returns a list containing nil for the data
228it can't find." 306it can't find."
229 (or 307 (unless calendar-current-time-zone-cache
230 calendar-current-time-zone-cache 308 (setq calendar-current-time-zone-cache (calendar-dst-find-data))))
231 (setq
232 calendar-current-time-zone-cache
233 (let* ((t0 (current-time))
234 (t0-zone (current-time-zone t0))
235 (t0-utc-diff (car t0-zone))
236 (t0-name (car (cdr t0-zone))))
237 (if (not t0-utc-diff)
238 ;; Little or no time zone information is available.
239 (list nil nil t0-name t0-name nil nil nil nil)
240 (let* ((t1 (calendar-next-time-zone-transition t0))
241 (t2 (and t1 (calendar-next-time-zone-transition t1))))
242 (if (not t2)
243 ;; This locale does not have daylight savings time.
244 (list (/ t0-utc-diff 60) 0 t0-name t0-name nil nil 0 0)
245 ;; Use heuristics to find daylight savings parameters.
246 (let* ((t1-zone (current-time-zone t1))
247 (t1-utc-diff (car t1-zone))
248 (t1-name (car (cdr t1-zone)))
249 (t1-date-sec (calendar-absolute-from-time t1 t0-utc-diff))
250 (t2-date-sec (calendar-absolute-from-time t2 t1-utc-diff))
251 (t1-rules (calendar-time-zone-daylight-rules
252 (car t1-date-sec) t0-utc-diff))
253 (t2-rules (calendar-time-zone-daylight-rules
254 (car t2-date-sec) t1-utc-diff))
255 (t1-time (/ (cdr t1-date-sec) 60))
256 (t2-time (/ (cdr t2-date-sec) 60)))
257 (cons
258 (/ (min t0-utc-diff t1-utc-diff) 60)
259 (cons
260 (/ (abs (- t0-utc-diff t1-utc-diff)) 60)
261 (if (< t0-utc-diff t1-utc-diff)
262 (list t0-name t1-name t1-rules t2-rules t1-time t2-time)
263 (list t1-name t0-name t2-rules t1-rules t2-time t1-time)
264 )))))))))))
265 309
266;;; The following eight defvars relating to daylight savings time should NOT be 310;;; The following eight defvars relating to daylight savings time should NOT be
267;;; marked to go into loaddefs.el where they would be evaluated when Emacs is 311;;; marked to go into loaddefs.el where they would be evaluated when Emacs is
@@ -293,12 +337,32 @@ For example, \"EST\" in New York City, \"PST\" for Los Angeles.")
293 "*Abbreviated name of daylight-savings time zone at `calendar-location-name'. 337 "*Abbreviated name of daylight-savings time zone at `calendar-location-name'.
294For example, \"EDT\" in New York City, \"PDT\" for Los Angeles.") 338For example, \"EDT\" in New York City, \"PDT\" for Los Angeles.")
295 339
340
341(defun calendar-dst-starts (year)
342 "Return the date of YEAR on which Daylight Saving Time starts.
343This function respects the value of `calendar-dst-check-each-year-flag'."
344 (or (let ((expr (if calendar-dst-check-each-year-flag
345 (cadr (calendar-dst-find-startend year))
346 (nth 4 calendar-current-time-zone-cache))))
347 (if expr (eval expr)))
348 (and (not (zerop calendar-daylight-time-offset))
349 (calendar-nth-named-day 1 0 4 year))))
350
351(defun calendar-dst-ends (year)
352 "Return the date of YEAR on which Daylight Saving Time ends.
353This function respects the value of `calendar-dst-check-each-year-flag'."
354 (or (let ((expr (if calendar-dst-check-each-year-flag
355 (nth 2 (calendar-dst-find-startend year))
356 (nth 5 calendar-current-time-zone-cache))))
357 (if expr (eval expr)))
358 (and (not (zerop calendar-daylight-time-offset))
359 (calendar-nth-named-day -1 0 10 year))))
360
361
296;;;###autoload 362;;;###autoload
297(put 'calendar-daylight-savings-starts 'risky-local-variable t) 363(put 'calendar-daylight-savings-starts 'risky-local-variable t)
298(defvar calendar-daylight-savings-starts 364(defvar calendar-daylight-savings-starts
299 (or (car (nthcdr 4 calendar-current-time-zone-cache)) 365 '(calendar-dst-starts year)
300 (and (not (zerop calendar-daylight-time-offset))
301 '(calendar-nth-named-day 1 0 4 year)))
302 "*Sexp giving the date on which daylight savings time starts. 366 "*Sexp giving the date on which daylight savings time starts.
303This is an expression in the variable `year' whose value gives the Gregorian 367This is an expression in the variable `year' whose value gives the Gregorian
304date in the form (month day year) on which daylight savings time starts. It is 368date in the form (month day year) on which daylight savings time starts. It is
@@ -319,9 +383,7 @@ If the locale never uses daylight savings time, set this to nil.")
319;;;###autoload 383;;;###autoload
320(put 'calendar-daylight-savings-ends 'risky-local-variable t) 384(put 'calendar-daylight-savings-ends 'risky-local-variable t)
321(defvar calendar-daylight-savings-ends 385(defvar calendar-daylight-savings-ends
322 (or (car (nthcdr 5 calendar-current-time-zone-cache)) 386 '(calendar-dst-ends year)
323 (and (not (zerop calendar-daylight-time-offset))
324 '(calendar-nth-named-day -1 0 10 year)))
325 "*Sexp giving the date on which daylight savings time ends. 387 "*Sexp giving the date on which daylight savings time ends.
326This is an expression in the variable `year' whose value gives the Gregorian 388This is an expression in the variable `year' whose value gives the Gregorian
327date in the form (month day year) on which daylight savings time ends. It is 389date in the form (month day year) on which daylight savings time ends. It is