aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Eggert1993-08-28 04:14:25 +0000
committerPaul Eggert1993-08-28 04:14:25 +0000
commit6bc457fea523673a7f898e9e14d3c652b3d66653 (patch)
tree36977646fa6034db81405256cf507c9405212d85
parent04d5d338d295fa4f7c19f480f2e123c297f02f39 (diff)
downloademacs-6bc457fea523673a7f898e9e14d3c652b3d66653.tar.gz
emacs-6bc457fea523673a7f898e9e14d3c652b3d66653.zip
(calendar-time-zone-daylight-rules): Scan through the
next few years until at most one rule remains; if none remain, then just use the first candidate rule; it's wrong in general, but it's right for at least one year. This is a better heuristic in case the underlying time zone implementation has bugs (which is all too common). If possible, don't convert back and forth between gregorian and absolute; this speeds things up noticeably. This uses the new calendar-nth-named-absday function. (calendar-current-time-zone): Some locales start DST at a different time of day than they end; allow for this by yielding both times. The performance speedups in calendar.el are great enough that we now no longer need the "Checking time zone data..." message. If current-time-zone yields nil, don't bother with calendar-next-time-zone-transition. Use clearer names for local vars. (calendar-time-zone, calendar-daylight-time-offset, calendar-{standard,daylight}-time-zone-name, calendar-daylight-savings-{starts,ends}): Default to US Eastern rules for information that is not available. (calendar-daylight-savings-{starts,ends}-time): New vars, replacing calendar-daylight-savings-switchover-time, to support locales that start DST at a different time of day than they end. (calendar-absolute-from-time): Fix typo by interchanging floor and mod.
-rw-r--r--lisp/calendar/cal-dst.el169
1 files changed, 94 insertions, 75 deletions
diff --git a/lisp/calendar/cal-dst.el b/lisp/calendar/cal-dst.el
index 62ca6b089a1..2608a15c17c 100644
--- a/lisp/calendar/cal-dst.el
+++ b/lisp/calendar/cal-dst.el
@@ -62,9 +62,9 @@ absolute date ABS-DATE is the equivalent moment to X."
62 ;; Overflow is a terrible thing! 62 ;; Overflow is a terrible thing!
63 (cons (+ calendar-system-time-basis 63 (cons (+ calendar-system-time-basis
64 ;; floor((2^16 h +l) / (60*60*24)) 64 ;; floor((2^16 h +l) / (60*60*24))
65 (* 512 (mod h 675)) (floor u 675)) 65 (* 512 (floor h 675)) (floor u 675))
66 ;; (2^16 h +l) % (60*60*24) 66 ;; (2^16 h +l) % (60*60*24)
67 (+ (* (mod u 675) 128) (floor l 128))))) 67 (+ (* (mod u 675) 128) (mod l 128)))))
68 68
69(defun calendar-time-from-absolute (abs-date s) 69(defun calendar-time-from-absolute (abs-date s)
70 "Time of absolute date ABS-DATE, S seconds after midnight. 70 "Time of absolute date ABS-DATE, S seconds after midnight.
@@ -169,32 +169,44 @@ The result has the proper form for calendar-daylight-savings-starts'."
169 (- (calendar-absolute-from-hebrew 169 (- (calendar-absolute-from-hebrew
170 (list 7 1 (+ year 3761))) 3)))))))) 170 (list 7 1 (+ year 3761))) 3))))))))
171 (prevday-sec (- -1 utc-diff)) ;; last sec of previous local day 171 (prevday-sec (- -1 utc-diff)) ;; last sec of previous local day
172 last-surviving-rule 172 (year (1+ y)))
173 (i 1)) 173 ;; Scan through the next few years until only one rule remains.
174 ;; Scan through the next few years; take the rule that explains them best. 174 (while
175 (while (and candidate-rules (cdr candidate-rules) (<= i 28)) 175 (let ((rules candidate-rules)
176 (let ((year (+ y i)) 176 new-rules)
177 new-rules) 177 (while
178 (while candidate-rules 178 (let*
179 (let* ((rule (car candidate-rules)) 179 ((rule (car rules))
180 (date (calendar-absolute-from-gregorian (eval rule)))) 180 (date
181 (or (equal (current-time-zone 181 ;; The following is much faster than
182 (calendar-time-from-absolute date prevday-sec)) 182 ;; (calendar-absolute-from-gregorian (eval rule)).
183 (current-time-zone 183 (cond ((eq (car rule) 'calendar-nth-named-day)
184 (calendar-time-from-absolute (1+ date) prevday-sec))) 184 (eval (cons 'calendar-nth-named-absday (cdr rule))))
185 (progn 185 ((eq (car rule) 'calendar-gregorian-from-absolute)
186 (setq new-rules (cons rule new-rules)) 186 (eval (car (cdr rule))))
187 (setq last-surviving-rule rule)))) 187 (t (let ((g (eval rule)))
188 (setq candidate-rules (cdr candidate-rules))) 188 (calendar-absolute-from-gregorian g))))))
189 (setq candidate-rules (nreverse new-rules))) 189 (or (equal
190 (setq i (1+ i))) 190 (current-time-zone
191 last-surviving-rule)) 191 (calendar-time-from-absolute date prevday-sec))
192 (current-time-zone
193 (calendar-time-from-absolute (1+ date) prevday-sec)))
194 (setq new-rules (cons rule new-rules)))
195 (setq rules (cdr rules))))
196 ;; If no rules remain, just use the first candidate rule;
197 ;; it's wrong in general, but it's right for at least one year.
198 (setq candidate-rules (if new-rules (nreverse new-rules)
199 (list (car candidate-rules))))
200 (setq year (1+ year))
201 (cdr candidate-rules)))
202 (car candidate-rules)))
192 203
193(defun calendar-current-time-zone () 204(defun calendar-current-time-zone ()
194 "Return UTC difference, dst offset, names and rules for current time zone. 205 "Return UTC difference, dst offset, names and rules for current time zone.
195 206
196Returns (UTC-DIFF DST-OFFSET STD-ZONE DST-ZONE DST-STARTS DST-ENDS DST-SWITCH), 207Returns (UTC-DIFF DST-OFFSET STD-ZONE DST-ZONE DST-STARTS DST-ENDS
197based on a heuristic probing of what the system knows: 208DST-STARTS-TIME DST-ENDS-TIME), based on a heuristic probing of what the
209system knows:
198 210
199UTC-DIFF is an integer specifying the number of minutes difference between 211UTC-DIFF is an integer specifying the number of minutes difference between
200 standard time in the current time zone and Coordinated Universal Time 212 standard time in the current time zone and Coordinated Universal Time
@@ -205,87 +217,88 @@ STD-ZONE is a string giving the name of the time zone when no seasonal time
205DST-ZONE is a string giving the name of the time zone when there is a seasonal 217DST-ZONE is a string giving the name of the time zone when there is a seasonal
206 time adjustment in effect. 218 time adjustment in effect.
207DST-STARTS and DST-ENDS are sexps in the variable `year' giving the daylight 219DST-STARTS and DST-ENDS are sexps in the variable `year' giving the daylight
208 savings time start rules, in the form expected by 220 savings time start and end rules, in the form expected by
209 `calendar-daylight-savings-starts'. 221 `calendar-daylight-savings-starts'.
210DST-SWITCH is an integer giving the number of minutes after midnight that 222DST-STARTS-TIME and DST-ENDS-TIME are integers giving the number of minutes
211 daylight savings time starts or ends. 223 after midnight that daylight savings time starts and ends.
212 224
213If the local area does not use a seasonal time adjustment, DST-OFFSET and 225If the local area does not use a seasonal time adjustment, STD-ZONE and
214DST-SWITCH are 0, STD-ZONE and DST-ZONE are equal, and DST-STARTS and DST-ENDS 226DST-ZONE are equal, and all the DST-* integer variables are 0.
215are nil.
216 227
217Some operating systems cannot provide all this information to Emacs; in this 228Some operating systems cannot provide all this information to Emacs; in this
218case, `calendar-current-time-zone' returns a list containing nil for the data 229case, `calendar-current-time-zone' returns a list containing nil for the data
219it can't find." 230it can't find."
220 (or 231 (or
221 calendar-current-time-zone-cache 232 calendar-current-time-zone-cache
222 (progn 233 (setq
223 (message "Checking time zone data...") 234 calendar-current-time-zone-cache
224 (setq 235 (let* ((t0 (current-time))
225 calendar-current-time-zone-cache 236 (t0-zone (current-time-zone t0))
226 (let* ((now (current-time)) 237 (t0-utc-diff (car t0-zone))
227 (now-zone (current-time-zone now)) 238 (t0-name (car (cdr t0-zone))))
228 (now-utc-diff (car now-zone)) 239 (if (not t0-utc-diff)
229 (now-name (car (cdr now-zone))) 240 ;; Little or no time zone information is available.
230 (next (calendar-next-time-zone-transition now))) 241 (list nil nil t0-name t0-name nil nil nil nil)
231 (if (null next) 242 (let* ((t1 (calendar-next-time-zone-transition t0))
232 (list (and now-utc-diff (/ now-utc-diff 60)) 243 (t2 (and t1 (calendar-next-time-zone-transition t1))))
233 0 now-name now-name nil nil 0) 244 (if (not t2)
234 (let* ((next-zone (current-time-zone next)) 245 ;; This locale does not have daylight savings time.
235 (next-utc-diff (car next-zone)) 246 (list (/ t0-utc-diff 60) 0 t0-name t0-name nil nil 0 0)
236 (next-name (car (cdr next-zone))) 247 ;; Use heuristics to find daylight savings parameters.
237 (next-absdate-seconds 248 (let* ((t1-zone (current-time-zone t1))
238 (calendar-absolute-from-time next now-utc-diff)) 249 (t1-utc-diff (car t1-zone))
239 (next-transitions 250 (t1-name (car (cdr t1-zone)))
240 (calendar-time-zone-daylight-rules 251 (t1-date-sec (calendar-absolute-from-time t1 t0-utc-diff))
241 (car next-absdate-seconds) now-utc-diff)) 252 (t2-date-sec (calendar-absolute-from-time t2 t1-utc-diff))
242 (nextnext (calendar-next-time-zone-transition next)) 253 (t1-rules (calendar-time-zone-daylight-rules
243 (now-transitions 254 (car t1-date-sec) t0-utc-diff))
244 (calendar-time-zone-daylight-rules 255 (t2-rules (calendar-time-zone-daylight-rules
245 (car (calendar-absolute-from-time nextnext next-utc-diff)) 256 (car t2-date-sec) t1-utc-diff))
246 next-utc-diff)) 257 (t1-time (/ (cdr t1-date-sec) 60))
247 (now-is-std (< now-utc-diff next-utc-diff))) 258 (t2-time (/ (cdr t2-date-sec) 60)))
248 (list (/ (min now-utc-diff next-utc-diff) 60) 259 (cons
249 (/ (abs (- now-utc-diff next-utc-diff)) 60) 260 (/ (min t0-utc-diff t1-utc-diff) 60)
250 (if now-is-std now-name next-name) 261 (cons
251 (if now-is-std next-name now-name) 262 (/ (abs (- t0-utc-diff t1-utc-diff)) 60)
252 (if now-is-std next-transitions now-transitions) 263 (if (< t0-utc-diff t1-utc-diff)
253 (if now-is-std now-transitions next-transitions) 264 (list t0-name t1-name t1-rules t2-rules t2-time t1-time)
254 (/ (cdr next-absdate-seconds) 60)))))) 265 (list t1-name t0-name t2-rules t1-rules t1-time t2-time)
255 (message "Checking time zone data...done"))) 266 )))))))))))
256 calendar-current-time-zone-cache)
257 267
258;;; The following six defvars relating to daylight savings time should NOT be 268;;; The following six defvars relating to daylight savings time should NOT be
259;;; marked to go into loaddefs.el where they would be evaluated when Emacs is 269;;; marked to go into loaddefs.el where they would be evaluated when Emacs is
260;;; dumped. These variables' appropriate values depend on the conditions under 270;;; dumped. These variables' appropriate values depend on the conditions under
261;;; which the code is INVOKED; so it's inappropriate to initialize them when 271;;; which the code is INVOKED; so it's inappropriate to initialize them when
262;;; Emacs is dumped---they should be initialized when calendar.el is loaded. 272;;; Emacs is dumped---they should be initialized when calendar.el is loaded.
273;;; They default to US Eastern time if time zone info is not available.
263 274
264(calendar-current-time-zone) 275(calendar-current-time-zone)
265 276
266(defvar calendar-time-zone (car calendar-current-time-zone-cache) 277(defvar calendar-time-zone (or (car calendar-current-time-zone-cache) -300)
267 "*Number of minutes difference between local standard time at 278 "*Number of minutes difference between local standard time at
268`calendar-location-name' and Coordinated Universal (Greenwich) Time. For 279`calendar-location-name' and Coordinated Universal (Greenwich) Time. For
269example, -300 for New York City, -480 for Los Angeles.") 280example, -300 for New York City, -480 for Los Angeles.")
270 281
271(defvar calendar-daylight-time-offset 282(defvar calendar-daylight-time-offset
272 (car (cdr calendar-current-time-zone-cache)) 283 (or (car (cdr calendar-current-time-zone-cache)) 60)
273 "*Number of minutes difference between daylight savings and standard time. 284 "*Number of minutes difference between daylight savings and standard time.
274 285
275If the locale never uses daylight savings time, set this to 0.") 286If the locale never uses daylight savings time, set this to 0.")
276 287
277(defvar calendar-standard-time-zone-name 288(defvar calendar-standard-time-zone-name
278 (car (nthcdr 2 calendar-current-time-zone-cache)) 289 (or (car (nthcdr 2 calendar-current-time-zone-cache)) "EST")
279 "*Abbreviated name of standard time zone at `calendar-location-name'. 290 "*Abbreviated name of standard time zone at `calendar-location-name'.
280For example, \"EST\" in New York City, \"PST\" for Los Angeles.") 291For example, \"EST\" in New York City, \"PST\" for Los Angeles.")
281 292
282(defvar calendar-daylight-time-zone-name 293(defvar calendar-daylight-time-zone-name
283 (car (nthcdr 3 calendar-current-time-zone-cache)) 294 (or (car (nthcdr 3 calendar-current-time-zone-cache)) "EDT")
284 "*Abbreviated name of daylight-savings time zone at `calendar-location-name'. 295 "*Abbreviated name of daylight-savings time zone at `calendar-location-name'.
285For example, \"EDT\" in New York City, \"PDT\" for Los Angeles.") 296For example, \"EDT\" in New York City, \"PDT\" for Los Angeles.")
286 297
287(defvar calendar-daylight-savings-starts 298(defvar calendar-daylight-savings-starts
288 (car (nthcdr 4 calendar-current-time-zone-cache)) 299 (or (car (nthcdr 4 calendar-current-time-zone-cache))
300 (and (not (zerop calendar-daylight-time-offset))
301 '(calendar-nth-named-day 1 0 4 year)))
289 "*Sexp giving the date on which daylight savings time starts. 302 "*Sexp giving the date on which daylight savings time starts.
290This is an expression in the variable `year' whose value gives the Gregorian 303This is an expression in the variable `year' whose value gives the Gregorian
291date in the form (month day year) on which daylight savings time starts. It is 304date in the form (month day year) on which daylight savings time starts. It is
@@ -310,7 +323,9 @@ because Nisan is the first month in the Hebrew calendar.
310If the locale never uses daylight savings time, set this to nil.") 323If the locale never uses daylight savings time, set this to nil.")
311 324
312(defvar calendar-daylight-savings-ends 325(defvar calendar-daylight-savings-ends
313 (car (nthcdr 5 calendar-current-time-zone-cache)) 326 (or (car (nthcdr 5 calendar-current-time-zone-cache))
327 (and (not (zerop calendar-daylight-time-offset))
328 '(calendar-nth-named-day -1 0 10 year)))
314 "*Sexp giving the date on which daylight savings time ends. 329 "*Sexp giving the date on which daylight savings time ends.
315This is an expression in the variable `year' whose value gives the Gregorian 330This is an expression in the variable `year' whose value gives the Gregorian
316date in the form (month day year) on which daylight savings time ends. It is 331date in the form (month day year) on which daylight savings time ends. It is
@@ -327,10 +342,14 @@ begins:
327 342
328If the locale never uses daylight savings time, set this to nil.") 343If the locale never uses daylight savings time, set this to nil.")
329 344
330(defvar calendar-daylight-savings-switchover-time 345(defvar calendar-daylight-savings-starts-time
331 (car (nthcdr 6 calendar-current-time-zone-cache)) 346 (or (car (nthcdr 6 calendar-current-time-zone-cache)) 120)
332 "*Number of minutes after midnight that daylight savings time begins/ends. 347 "*Number of minutes after midnight that daylight savings time starts.")
333If the locale never uses daylight savings time, set this to 0.") 348
349(defvar calendar-daylight-savings-ends-time
350 (or (car (nthcdr 7 calendar-current-time-zone-cache))
351 calendar-daylight-savings-starts-time)
352 "*Number of minutes after midnight that daylight savings time ends.")
334 353
335(provide 'cal-dst) 354(provide 'cal-dst)
336 355