diff options
| author | Glenn Morris | 2006-11-10 08:54:38 +0000 |
|---|---|---|
| committer | Glenn Morris | 2006-11-10 08:54:38 +0000 |
| commit | cd72c39915f4d43a286f1a193ee950c8c8049c10 (patch) | |
| tree | aff1d61ee71fe6e79a79f98e85ddaa9ee02a739f | |
| parent | 86f46920ffbadd4fc01b3e28aa6ea82bc04184e8 (diff) | |
| download | emacs-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.el | 146 |
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. | ||
| 47 | nil means to assume the next two transitions found after the | ||
| 48 | current date apply to all years. This is faster, but not always | ||
| 49 | correct, since the dates of Daylight Saving transitions sometimes | ||
| 50 | change." | ||
| 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. | ||
| 218 | TIME defaults to `current-time'. Return value is as described | ||
| 219 | for `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. | ||
| 257 | Value is a list with elements of the form (YEAR START END), where | ||
| 258 | START and END are expressions that when evaluated return the | ||
| 259 | start and end dates (respectively) for DST in YEAR. Used by the | ||
| 260 | function `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. | ||
| 264 | Returns a list (YEAR START END), where START and END are | ||
| 265 | expressions that when evaluated return the start and end dates, | ||
| 266 | respectively. This function first attempts to use pre-calculated | ||
| 267 | data 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. | |||
| 226 | Some operating systems cannot provide all this information to Emacs; in this | 304 | Some operating systems cannot provide all this information to Emacs; in this |
| 227 | case, `calendar-current-time-zone' returns a list containing nil for the data | 305 | case, `calendar-current-time-zone' returns a list containing nil for the data |
| 228 | it can't find." | 306 | it 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'. |
| 294 | For example, \"EDT\" in New York City, \"PDT\" for Los Angeles.") | 338 | For 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. | ||
| 343 | This 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. | ||
| 353 | This 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. |
| 303 | This is an expression in the variable `year' whose value gives the Gregorian | 367 | This is an expression in the variable `year' whose value gives the Gregorian |
| 304 | date in the form (month day year) on which daylight savings time starts. It is | 368 | date 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. |
| 326 | This is an expression in the variable `year' whose value gives the Gregorian | 388 | This is an expression in the variable `year' whose value gives the Gregorian |
| 327 | date in the form (month day year) on which daylight savings time ends. It is | 389 | date in the form (month day year) on which daylight savings time ends. It is |