aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHong Xu2016-12-24 14:35:12 +0200
committerEli Zaretskii2016-12-24 14:35:12 +0200
commit25c9cb77b4346c9912c995ca3a63fc7ab424795e (patch)
tree1b450c512afd6cbd8cbd3519797369c16accb1cb
parente36a3882c338765a9ddfebfc160e5a298933f233 (diff)
downloademacs-25c9cb77b4346c9912c995ca3a63fc7ab424795e.tar.gz
emacs-25c9cb77b4346c9912c995ca3a63fc7ab424795e.zip
Fix timezone detection of parse-iso8601-time-string
* parse-time.el (parse-iso8601-time-string): Fix timezone parsing. Add a doc string. (Bug#25086) * editfns.c (Fdecode-time): Doc fix. * emacs-mime.texi (time-date): Add an example for parse-iso8601-time-string. * parse-time-tests.el (parse-time-tests): Add tests for parse-iso8601-time-string.
-rw-r--r--doc/misc/emacs-mime.texi3
-rw-r--r--lisp/calendar/parse-time.el26
-rw-r--r--src/editfns.c2
-rw-r--r--test/lisp/calendar/parse-time-tests.el18
4 files changed, 40 insertions, 9 deletions
diff --git a/doc/misc/emacs-mime.texi b/doc/misc/emacs-mime.texi
index 2b935870dae..9389435faf1 100644
--- a/doc/misc/emacs-mime.texi
+++ b/doc/misc/emacs-mime.texi
@@ -1536,6 +1536,9 @@ Here's a bunch of time/date/second/day examples:
1536(date-to-time "Sat Sep 12 12:21:54 1998 +0200") 1536(date-to-time "Sat Sep 12 12:21:54 1998 +0200")
1537@result{} (13818 19266) 1537@result{} (13818 19266)
1538 1538
1539(parse-iso8601-time-string "1998-09-12T12:21:54+0200")
1540@result{} (13818 19266)
1541
1539(float-time '(13818 19266)) 1542(float-time '(13818 19266))
1540@result{} 905595714.0 1543@result{} 905595714.0
1541 1544
diff --git a/lisp/calendar/parse-time.el b/lisp/calendar/parse-time.el
index b62f9fa7941..ef7758df442 100644
--- a/lisp/calendar/parse-time.el
+++ b/lisp/calendar/parse-time.el
@@ -202,7 +202,7 @@ any values that are unknown are returned as nil."
202 (time-minute 2digit) 202 (time-minute 2digit)
203 (time-second 2digit) 203 (time-second 2digit)
204 (time-secfrac "\\(\\.[0-9]+\\)?") 204 (time-secfrac "\\(\\.[0-9]+\\)?")
205 (time-numoffset (concat "[-+]\\(" time-hour "\\):" time-minute)) 205 (time-numoffset (concat "\\([-+]\\)" time-hour ":?" time-minute "?"))
206 (time-offset (concat "Z" time-numoffset)) 206 (time-offset (concat "Z" time-numoffset))
207 (partial-time (concat time-hour colon time-minute colon time-second 207 (partial-time (concat time-hour colon time-minute colon time-second
208 time-secfrac)) 208 time-secfrac))
@@ -211,19 +211,22 @@ any values that are unknown are returned as nil."
211 (date-time (concat full-date "T" full-time))) 211 (date-time (concat full-date "T" full-time)))
212 (list (concat "^" full-date) 212 (list (concat "^" full-date)
213 (concat "T" partial-time) 213 (concat "T" partial-time)
214 (concat "Z" time-numoffset))) 214 (concat "\\(Z\\|" time-numoffset "\\)")))
215 "List of regular expressions matching ISO 8601 dates. 215 "List of regular expressions matching ISO 8601 dates.
2161st regular expression matches the date. 2161st regular expression matches the date.
2172nd regular expression matches the time. 2172nd regular expression matches the time.
2183rd regular expression matches the (optional) timezone specification.") 2183rd regular expression matches the (optional) timezone specification.")
219 219
220(defun parse-iso8601-time-string (date-string) 220(defun parse-iso8601-time-string (date-string)
221 "Parse an ISO 8601 time string, such as 2016-12-01T23:35:06-05:00.
222If DATE-STRING cannot be parsed, it falls back to
223`parse-time-string'."
221 (let* ((date-re (nth 0 parse-time-iso8601-regexp)) 224 (let* ((date-re (nth 0 parse-time-iso8601-regexp))
222 (time-re (nth 1 parse-time-iso8601-regexp)) 225 (time-re (nth 1 parse-time-iso8601-regexp))
223 (tz-re (nth 2 parse-time-iso8601-regexp)) 226 (tz-re (nth 2 parse-time-iso8601-regexp))
224 re-start 227 re-start
225 time seconds minute hour fractional-seconds 228 time seconds minute hour fractional-seconds
226 day month year day-of-week dst tz) 229 day month year day-of-week dst tz)
227 ;; We need to populate 'time' with 230 ;; We need to populate 'time' with
228 ;; (SEC MIN HOUR DAY MON YEAR DOW DST TZ) 231 ;; (SEC MIN HOUR DAY MON YEAR DOW DST TZ)
229 232
@@ -242,10 +245,19 @@ any values that are unknown are returned as nil."
242 "0")) 245 "0"))
243 re-start (match-end 0)) 246 re-start (match-end 0))
244 (when (string-match tz-re date-string re-start) 247 (when (string-match tz-re date-string re-start)
245 (setq tz (match-string 1 date-string))) 248 (if (string= "Z" (match-string 1 date-string))
249 (setq tz 0) ;; UTC timezone indicated by Z
250 (setq tz (+
251 (* 3600
252 (string-to-number (match-string 3 date-string)))
253 (* 60
254 (string-to-number
255 (or (match-string 4 date-string) "0")))))
256 (when (string= "-" (match-string 2 date-string))
257 (setq tz (- tz)))))
246 (setq time (list seconds minute hour day month year day-of-week dst tz)))) 258 (setq time (list seconds minute hour day month year day-of-week dst tz))))
247 259
248 ;; Fall back to having Gnus do fancy things for us. 260 ;; Fall back to having `parse-time-string' do fancy things for us.
249 (when (not time) 261 (when (not time)
250 (setq time (parse-time-string date-string))) 262 (setq time (parse-time-string date-string)))
251 263
diff --git a/src/editfns.c b/src/editfns.c
index 6ea8cbaf5e4..ccc78e12758 100644
--- a/src/editfns.c
+++ b/src/editfns.c
@@ -2136,7 +2136,7 @@ format_time_string (char const *format, ptrdiff_t formatlen,
2136 2136
2137DEFUN ("decode-time", Fdecode_time, Sdecode_time, 0, 2, 0, 2137DEFUN ("decode-time", Fdecode_time, Sdecode_time, 0, 2, 0,
2138 doc: /* Decode a time value as (SEC MINUTE HOUR DAY MONTH YEAR DOW DST UTCOFF). 2138 doc: /* Decode a time value as (SEC MINUTE HOUR DAY MONTH YEAR DOW DST UTCOFF).
2139The optional SPECIFIED-TIME should be a list of (HIGH LOW . IGNORED), 2139The optional TIME should be a list of (HIGH LOW . IGNORED),
2140as from `current-time' and `file-attributes', or nil to use the 2140as from `current-time' and `file-attributes', or nil to use the
2141current time. It can also be a single integer number of seconds since 2141current time. It can also be a single integer number of seconds since
2142the epoch. The obsolete form (HIGH . LOW) is also still accepted. 2142the epoch. The obsolete form (HIGH . LOW) is also still accepted.
diff --git a/test/lisp/calendar/parse-time-tests.el b/test/lisp/calendar/parse-time-tests.el
index 9bcf2b4a53c..6dc23372f24 100644
--- a/test/lisp/calendar/parse-time-tests.el
+++ b/test/lisp/calendar/parse-time-tests.el
@@ -42,7 +42,23 @@
42 (should (equal (parse-time-string "Monday, 22 february 2016 19:35:42 +0100") 42 (should (equal (parse-time-string "Monday, 22 february 2016 19:35:42 +0100")
43 '(42 35 19 22 2 2016 1 nil 3600))) 43 '(42 35 19 22 2 2016 1 nil 3600)))
44 (should (equal (parse-time-string "Monday, 22 february 2016 19:35:42 PDT") 44 (should (equal (parse-time-string "Monday, 22 february 2016 19:35:42 PDT")
45 '(42 35 19 22 2 2016 1 t -25200)))) 45 '(42 35 19 22 2 2016 1 t -25200)))
46 (should (equal (parse-iso8601-time-string "1998-09-12T12:21:54-0200")
47 '(13818 33666)))
48 (should (equal (parse-iso8601-time-string "1998-09-12T12:21:54-0230")
49 '(13818 35466)))
50 (should (equal (parse-iso8601-time-string "1998-09-12T12:21:54-02:00")
51 '(13818 33666)))
52 (should (equal (parse-iso8601-time-string "1998-09-12T12:21:54-02")
53 '(13818 33666)))
54 (should (equal (parse-iso8601-time-string "1998-09-12T12:21:54+0230")
55 '(13818 17466)))
56 (should (equal (parse-iso8601-time-string "1998-09-12T12:21:54+02")
57 '(13818 19266)))
58 (should (equal (parse-iso8601-time-string "1998-09-12T12:21:54Z")
59 '(13818 26466)))
60 (should (equal (parse-iso8601-time-string "1998-09-12T12:21:54")
61 (encode-time 54 21 12 12 9 1998))))
46 62
47(provide 'parse-time-tests) 63(provide 'parse-time-tests)
48 64