Mercurial > hg > xemacs-beta
comparison lisp/utils/timezone.el @ 0:376386a54a3c r19-14
Import from CVS: tag r19-14
author | cvs |
---|---|
date | Mon, 13 Aug 2007 08:45:50 +0200 |
parents | |
children | 0293115a14e9 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:376386a54a3c |
---|---|
1 ;;; timezone.el --- time zone package for GNU Emacs | |
2 | |
3 ;; Copyright (C) 1990, 1991, 1992, 1993 Free Software Foundation, Inc. | |
4 | |
5 ;; Author: Masanobu Umeda | |
6 ;; Maintainer: umerin@mse.kyutech.ac.jp | |
7 ;; Keywords: news | |
8 | |
9 ;; This file is part of XEmacs. | |
10 | |
11 ;; XEmacs is free software; you can redistribute it and/or modify it | |
12 ;; under the terms of the GNU General Public License as published by | |
13 ;; the Free Software Foundation; either version 2, or (at your option) | |
14 ;; any later version. | |
15 | |
16 ;; XEmacs is distributed in the hope that it will be useful, but | |
17 ;; WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
19 ;; General Public License for more details. | |
20 | |
21 ;; You should have received a copy of the GNU General Public License | |
22 ;; along with XEmacs; see the file COPYING. If not, write to the Free | |
23 ;; Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | |
24 | |
25 ;;; Synched up with: FSF 19.30. | |
26 | |
27 ;; Modified 1 February 1994 by Kyle Jones to fix broken | |
28 ;; timezone-floor function. | |
29 | |
30 ;; Modified 25 January 1994 by Kyle Jones so that it will | |
31 ;; work under version 18 of Emacs. Provided timezone-floor | |
32 ;; and timezone-abs functions. | |
33 | |
34 ;;; Code: | |
35 | |
36 (provide 'timezone) | |
37 | |
38 (defvar timezone-world-timezones | |
39 '(("PST" . -800) | |
40 ("PDT" . -700) | |
41 ("MST" . -700) | |
42 ("MDT" . -600) | |
43 ("CST" . -600) | |
44 ("CDT" . -500) | |
45 ("EST" . -500) | |
46 ("EDT" . -400) | |
47 ("AST" . -400) ;by <clamen@CS.CMU.EDU> | |
48 ("NST" . -330) ;by <clamen@CS.CMU.EDU> | |
49 ("UT" . +000) | |
50 ("GMT" . +000) | |
51 ("BST" . +100) | |
52 ("MET" . +100) | |
53 ("EET" . +200) | |
54 ("JST" . +900) | |
55 ("GMT+1" . +100) ("GMT+2" . +200) ("GMT+3" . +300) | |
56 ("GMT+4" . +400) ("GMT+5" . +500) ("GMT+6" . +600) | |
57 ("GMT+7" . +700) ("GMT+8" . +800) ("GMT+9" . +900) | |
58 ("GMT+10" . +1000) ("GMT+11" . +1100) ("GMT+12" . +1200) ("GMT+13" . +1300) | |
59 ("GMT-1" . -100) ("GMT-2" . -200) ("GMT-3" . -300) | |
60 ("GMT-4" . -400) ("GMT-5" . -500) ("GMT-6" . -600) | |
61 ("GMT-7" . -700) ("GMT-8" . -800) ("GMT-9" . -900) | |
62 ("GMT-10" . -1000) ("GMT-11" . -1100) ("GMT-12" . -1200)) | |
63 "*Time differentials of timezone from GMT in +-HHMM form. | |
64 This list is obsolescent, and is present only for backwards compatibility, | |
65 because time zone names are ambiguous in practice. | |
66 Use `current-time-zone' instead.") | |
67 | |
68 (defvar timezone-months-assoc | |
69 '(("JAN" . 1)("FEB" . 2)("MAR" . 3) | |
70 ("APR" . 4)("MAY" . 5)("JUN" . 6) | |
71 ("JUL" . 7)("AUG" . 8)("SEP" . 9) | |
72 ("OCT" . 10)("NOV" . 11)("DEC" . 12)) | |
73 "Alist of first three letters of a month and its numerical representation.") | |
74 | |
75 (defun timezone-make-date-arpa-standard (date &optional local timezone) | |
76 "Convert DATE to an arpanet standard date. | |
77 Optional 1st argument LOCAL specifies the default local timezone of the DATE; | |
78 if nil, GMT is assumed. | |
79 Optional 2nd argument TIMEZONE specifies a time zone to be represented in; | |
80 if nil, the local time zone is assumed." | |
81 (let ((new (timezone-fix-time date local timezone))) | |
82 (timezone-make-arpa-date (aref new 0) (aref new 1) (aref new 2) | |
83 (timezone-make-time-string | |
84 (aref new 3) (aref new 4) (aref new 5)) | |
85 (aref new 6)) | |
86 )) | |
87 | |
88 (defun timezone-make-date-sortable (date &optional local timezone) | |
89 "Convert DATE to a sortable date string. | |
90 Optional 1st argument LOCAL specifies the default local timezone of the DATE; | |
91 if nil, GMT is assumed. | |
92 Optional 2nd argument TIMEZONE specifies a timezone to be represented in; | |
93 if nil, the local time zone is assumed." | |
94 (let ((new (timezone-fix-time date local timezone))) | |
95 (timezone-make-sortable-date (aref new 0) (aref new 1) (aref new 2) | |
96 (timezone-make-time-string | |
97 (aref new 3) (aref new 4) (aref new 5))) | |
98 )) | |
99 | |
100 | |
101 ;; | |
102 ;; Parsers and Constructors of Date and Time | |
103 ;; | |
104 | |
105 (defun timezone-make-arpa-date (year month day time &optional timezone) | |
106 "Make arpanet standard date string from YEAR, MONTH, DAY, and TIME. | |
107 Optional argument TIMEZONE specifies a time zone." | |
108 (let ((zone | |
109 (if (listp timezone) | |
110 (let* ((m (timezone-zone-to-minute timezone)) | |
111 (absm (if (< m 0) (- m) m))) | |
112 (format "%c%02d%02d" | |
113 (if (< m 0) ?- ?+) (/ absm 60) (% absm 60))) | |
114 timezone))) | |
115 (format "%02d %s %04d %s %s" | |
116 day | |
117 (capitalize (car (rassq month timezone-months-assoc))) | |
118 year | |
119 time | |
120 zone))) | |
121 | |
122 (defun timezone-make-sortable-date (year month day time) | |
123 "Make sortable date string from YEAR, MONTH, DAY, and TIME." | |
124 (format "%4d%02d%02d%s" | |
125 year month day time)) | |
126 | |
127 (defun timezone-make-time-string (hour minute second) | |
128 "Make time string from HOUR, MINUTE, and SECOND." | |
129 (format "%02d:%02d:%02d" hour minute second)) | |
130 | |
131 (defun timezone-parse-date (date) | |
132 "Parse DATE and return a vector [YEAR MONTH DAY TIME TIMEZONE]. | |
133 19 is prepended to year if necessary. Timezone may be nil if nothing. | |
134 Understands the following styles: | |
135 (1) 14 Apr 89 03:20[:12] [GMT] | |
136 (2) Fri, 17 Mar 89 4:01[:33] [GMT] | |
137 (3) Mon Jan 16 16:12[:37] [GMT] 1989 | |
138 (4) 6 May 1992 1641-JST (Wednesday) | |
139 (5) 22-AUG-1993 10:59:12.82 | |
140 (6) Thu, 11 Apr 16:17:12 91 [MET] | |
141 (7) Mon, 6 Jul 16:47:20 T 1992 [MET]" | |
142 ;; Get rid of any text properties. | |
143 (and (stringp date) | |
144 (or (text-properties-at 0 date) | |
145 (next-property-change 0 date)) | |
146 (setq date (copy-sequence date)) | |
147 (set-text-properties 0 (length date) nil date)) | |
148 (let ((date (or date "")) | |
149 (year nil) | |
150 (month nil) | |
151 (day nil) | |
152 (time nil) | |
153 (zone nil)) ;This may be nil. | |
154 (cond ((string-match | |
155 "\\([^ \t,]+\\),[ \t]+\\([0-9]+\\)[ \t]+\\([^ \t,]+\\)[ \t]+\\([0-9]+:[0-9:]+\\)[ \t]+\\(T[ \t]+\\|\\)\\([0-9]+\\)[ \t]*\\'" date) | |
156 ;; Styles: (6) and (7) without timezone | |
157 (setq year 6 month 3 day 2 time 4 zone nil)) | |
158 ((string-match | |
159 "\\([^ \t,]+\\),[ \t]+\\([0-9]+\\)[ \t]+\\([^ \t,]+\\)[ \t]+\\([0-9]+:[0-9:]+\\)[ \t]+\\(T[ \t]+\\|\\)\\([0-9]+\\)[ \t]*\\([-+a-zA-Z0-9]+\\)" date) | |
160 ;; Styles: (6) and (7) with timezone and buggy timezone | |
161 (setq year 6 month 3 day 2 time 4 zone 7)) | |
162 ((string-match | |
163 "\\([0-9]+\\)[ \t]+\\([^ \t,]+\\)[ \t]+\\([0-9]+\\)[ \t]+\\([0-9]+:[0-9:]+\\)[ \t]*\\'" date) | |
164 ;; Styles: (1) and (2) without timezone | |
165 (setq year 3 month 2 day 1 time 4 zone nil)) | |
166 ((string-match | |
167 "\\([0-9]+\\)[ \t]+\\([^ \t,]+\\)[ \t]+\\([0-9]+\\)[ \t]+\\([0-9]+:[0-9:]+\\)[ \t]*\\([-+a-zA-Z0-9]+\\)" date) | |
168 ;; Styles: (1) and (2) with timezone and buggy timezone | |
169 (setq year 3 month 2 day 1 time 4 zone 5)) | |
170 ((string-match | |
171 "\\([^ \t,]+\\)[ \t]+\\([0-9]+\\)[ \t]+\\([0-9]+:[0-9:]+\\)[ \t]+\\([0-9]+\\)" date) | |
172 ;; Styles: (3) without timezone | |
173 (setq year 4 month 1 day 2 time 3 zone nil)) | |
174 ((string-match | |
175 "\\([^ \t,]+\\)[ \t]+\\([0-9]+\\)[ \t]+\\([0-9]+:[0-9:]+\\)[ \t]+\\([-+a-zA-Z0-9]+\\)[ \t]+\\([0-9]+\\)" date) | |
176 ;; Styles: (3) with timezone | |
177 (setq year 5 month 1 day 2 time 3 zone 4)) | |
178 ((string-match | |
179 "\\([0-9]+\\)[ \t]+\\([^ \t,]+\\)[ \t]+\\([0-9]+\\)[ \t]+\\([0-9]+\\)[ \t]*\\([-+a-zA-Z0-9]+\\)" date) | |
180 ;; Styles: (4) with timezone | |
181 (setq year 3 month 2 day 1 time 4 zone 5)) | |
182 ((string-match | |
183 "\\([0-9]+\\)-\\([A-Za-z]+\\)-\\([0-9]+\\)[ \t]+\\([0-9]+:[0-9]+:[0-9]+\\)\\.[0-9]+" date) | |
184 ;; Styles: (5) without timezone. | |
185 (setq year 3 month 2 day 1 time 4 zone nil)) | |
186 ) | |
187 (if year | |
188 (progn | |
189 (setq year | |
190 (substring date (match-beginning year) (match-end year))) | |
191 ;; It is now Dec 1992. 8 years before the end of the World. | |
192 (if (< (length year) 4) | |
193 (setq year (concat "19" (substring year -2 nil)))) | |
194 (let ((string (substring date | |
195 (match-beginning month) | |
196 (+ (match-beginning month) 3)))) | |
197 (setq month | |
198 (int-to-string | |
199 (cdr (assoc (upcase string) timezone-months-assoc))))) | |
200 | |
201 (setq day | |
202 (substring date (match-beginning day) (match-end day))) | |
203 (setq time | |
204 (substring date (match-beginning time) (match-end time))))) | |
205 (if zone | |
206 (setq zone | |
207 (substring date (match-beginning zone) (match-end zone)))) | |
208 ;; Return a vector. | |
209 (if year | |
210 (vector year month day time zone) | |
211 (vector "0" "0" "0" "0" nil)) | |
212 )) | |
213 | |
214 (defun timezone-parse-time (time) | |
215 "Parse TIME (HH:MM:SS) and return a vector [hour minute second]. | |
216 Recognize HH:MM:SS, HH:MM, HHMMSS, HHMM." | |
217 (let ((time (or time "")) | |
218 (hour nil) | |
219 (minute nil) | |
220 (second nil)) | |
221 (cond ((string-match "\\`\\([0-9]+\\):\\([0-9]+\\):\\([0-9]+\\)\\'" time) | |
222 ;; HH:MM:SS | |
223 (setq hour 1 minute 2 second 3)) | |
224 ((string-match "\\`\\([0-9]+\\):\\([0-9]+\\)\\'" time) | |
225 ;; HH:MM | |
226 (setq hour 1 minute 2 second nil)) | |
227 ((string-match "\\`\\([0-9][0-9]\\)\\([0-9][0-9]\\)\\([0-9][0-9]\\)\\'" time) | |
228 ;; HHMMSS | |
229 (setq hour 1 minute 2 second 3)) | |
230 ((string-match "\\`\\([0-9][0-9]\\)\\([0-9][0-9]\\)\\'" time) | |
231 ;; HHMM | |
232 (setq hour 1 minute 2 second nil)) | |
233 ) | |
234 ;; Return [hour minute second] | |
235 (vector | |
236 (if hour | |
237 (substring time (match-beginning hour) (match-end hour)) "0") | |
238 (if minute | |
239 (substring time (match-beginning minute) (match-end minute)) "0") | |
240 (if second | |
241 (substring time (match-beginning second) (match-end second)) "0")) | |
242 )) | |
243 | |
244 | |
245 ;; Miscellaneous | |
246 | |
247 (defun timezone-zone-to-minute (timezone) | |
248 "Translate TIMEZONE to an integer minute offset from GMT. | |
249 TIMEZONE can be a cons cell containing the output of current-time-zone, | |
250 or an integer of the form +-HHMM, or a time zone name." | |
251 (cond | |
252 ((consp timezone) | |
253 (/ (car timezone) 60)) | |
254 (timezone | |
255 (progn | |
256 (setq timezone | |
257 (or (cdr (assoc (upcase timezone) timezone-world-timezones)) | |
258 ;; +900 | |
259 timezone)) | |
260 (if (stringp timezone) | |
261 (setq timezone (string-to-int timezone))) | |
262 ;; Taking account of minute in timezone. | |
263 ;; HHMM -> MM | |
264 (let* ((abszone (timezone-abs timezone)) | |
265 (minutes (+ (* 60 (/ abszone 100)) (% abszone 100)))) | |
266 (if (< timezone 0) (- minutes) minutes)))) | |
267 (t 0))) | |
268 | |
269 (defun timezone-time-from-absolute (date seconds) | |
270 "Compute the UTC time equivalent to DATE at time SECONDS after midnight. | |
271 Return a list suitable as an argument to current-time-zone, | |
272 or nil if the date cannot be thus represented. | |
273 DATE is the number of days elapsed since the (imaginary) | |
274 Gregorian date Sunday, December 31, 1 BC." | |
275 (let* ((current-time-origin 719162) | |
276 ;; (timezone-absolute-from-gregorian 1 1 1970) | |
277 (days (- date current-time-origin)) | |
278 (seconds-per-day (float 86400)) | |
279 (seconds (+ seconds (* days seconds-per-day))) | |
280 (current-time-arithmetic-base (float 65536)) | |
281 (hi (timezone-floor (/ seconds current-time-arithmetic-base))) | |
282 (hibase (* hi current-time-arithmetic-base)) | |
283 (lo (timezone-floor (- seconds hibase)))) | |
284 (and (< (timezone-abs (- seconds (+ hibase lo))) 2) ;; Check for integer overflow. | |
285 (cons hi lo)))) | |
286 | |
287 (defun timezone-time-zone-from-absolute (date seconds) | |
288 "Compute the local time zone for DATE at time SECONDS after midnight. | |
289 Return a list in the same format as current-time-zone's result, | |
290 or nil if the local time zone could not be computed. | |
291 DATE is the number of days elapsed since the (imaginary) | |
292 Gregorian date Sunday, December 31, 1 BC." | |
293 (and (fboundp 'current-time-zone) | |
294 (let ((utc-time (timezone-time-from-absolute date seconds))) | |
295 (and utc-time | |
296 (let ((zone (current-time-zone utc-time))) | |
297 (and (car zone) zone)))))) | |
298 | |
299 (defun timezone-fix-time (date local timezone) | |
300 "Convert DATE (default timezone LOCAL) to YYYY-MM-DD-HH-MM-SS-ZONE vector. | |
301 If LOCAL is nil, it is assumed to be GMT. | |
302 If TIMEZONE is nil, use the local time zone." | |
303 (let* ((date (timezone-parse-date date)) | |
304 (year (string-to-int (aref date 0))) | |
305 (year (cond ((< year 50) | |
306 (+ year 2000)) | |
307 ((< year 100) | |
308 (+ year 1900)) | |
309 (t year))) | |
310 (month (string-to-int (aref date 1))) | |
311 (day (string-to-int (aref date 2))) | |
312 (time (timezone-parse-time (aref date 3))) | |
313 (hour (string-to-int (aref time 0))) | |
314 (minute (string-to-int (aref time 1))) | |
315 (second (string-to-int (aref time 2))) | |
316 (local (or (aref date 4) local)) ;Use original if defined | |
317 (timezone | |
318 (or timezone | |
319 (timezone-time-zone-from-absolute | |
320 (timezone-absolute-from-gregorian month day year) | |
321 (+ second (* 60 (+ minute (* 60 hour))))))) | |
322 (diff (- (timezone-zone-to-minute timezone) | |
323 (timezone-zone-to-minute local))) | |
324 (minute (+ minute diff)) | |
325 (hour-fix (timezone-floor minute 60))) | |
326 (setq hour (+ hour hour-fix)) | |
327 (setq minute (- minute (* 60 hour-fix))) | |
328 ;; HOUR may be larger than 24 or smaller than 0. | |
329 (cond ((<= 24 hour) ;24 -> 00 | |
330 (setq hour (- hour 24)) | |
331 (setq day (1+ day)) | |
332 (if (< (timezone-last-day-of-month month year) day) | |
333 (progn | |
334 (setq month (1+ month)) | |
335 (setq day 1) | |
336 (if (< 12 month) | |
337 (progn | |
338 (setq month 1) | |
339 (setq year (1+ year)) | |
340 )) | |
341 ))) | |
342 ((> 0 hour) | |
343 (setq hour (+ hour 24)) | |
344 (setq day (1- day)) | |
345 (if (> 1 day) | |
346 (progn | |
347 (setq month (1- month)) | |
348 (if (> 1 month) | |
349 (progn | |
350 (setq month 12) | |
351 (setq year (1- year)) | |
352 )) | |
353 (setq day (timezone-last-day-of-month month year)) | |
354 ))) | |
355 ) | |
356 (vector year month day hour minute second timezone))) | |
357 | |
358 ;; Partly copied from Calendar program by Edward M. Reingold. | |
359 ;; Thanks a lot. | |
360 | |
361 (defun timezone-last-day-of-month (month year) | |
362 "The last day in MONTH during YEAR." | |
363 (if (and (= month 2) (timezone-leap-year-p year)) | |
364 29 | |
365 (aref [31 28 31 30 31 30 31 31 30 31 30 31] (1- month)))) | |
366 | |
367 (defun timezone-leap-year-p (year) | |
368 "Returns t if YEAR is a Gregorian leap year." | |
369 (or (and (zerop (% year 4)) | |
370 (not (zerop (% year 100)))) | |
371 (zerop (% year 400)))) | |
372 | |
373 (defun timezone-day-number (month day year) | |
374 "Return the day number within the year of the date month/day/year." | |
375 (let ((day-of-year (+ day (* 31 (1- month))))) | |
376 (if (> month 2) | |
377 (progn | |
378 (setq day-of-year (- day-of-year (/ (+ 23 (* 4 month)) 10))) | |
379 (if (timezone-leap-year-p year) | |
380 (setq day-of-year (1+ day-of-year))))) | |
381 day-of-year)) | |
382 | |
383 (defun timezone-absolute-from-gregorian (month day year) | |
384 "The number of days between the Gregorian date 12/31/1 BC and month/day/year. | |
385 The Gregorian date Sunday, December 31, 1 BC is imaginary." | |
386 (+ (timezone-day-number month day year);; Days this year | |
387 (* 365 (1- year));; + Days in prior years | |
388 (/ (1- year) 4);; + Julian leap years | |
389 (- (/ (1- year) 100));; - century years | |
390 (/ (1- year) 400)));; + Gregorian leap years | |
391 | |
392 (defun timezone-abs (n) | |
393 (if (fboundp 'abs) | |
394 (abs n) | |
395 (if (< n 0) (- n) n))) | |
396 | |
397 (defun timezone-floor (n &optional divisor) | |
398 (if (fboundp 'floor) | |
399 (floor n divisor) | |
400 (if (null divisor) | |
401 (setq divisor 1)) | |
402 (if (< n 0) | |
403 (- (/ (- divisor 1 n) divisor)) | |
404 (/ n divisor)))) | |
405 | |
406 ;;; timezone.el ends here |