aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars Ingebrigtsen2019-09-29 21:22:29 +0200
committerLars Ingebrigtsen2019-09-29 21:22:36 +0200
commit0df01e3aa5f8372995bdc39be36c444c54a52f7e (patch)
tree7b26486c46b31fae0cbbc19dbca78a476235c5ed
parent53ebec24c871c5e6adb6aed088199d1b15e0198a (diff)
downloademacs-0df01e3aa5f8372995bdc39be36c444c54a52f7e.tar.gz
emacs-0df01e3aa5f8372995bdc39be36c444c54a52f7e.zip
Add support for sub-second ISO8601 strings
* lisp/calendar/iso8601.el (iso8601--decimalize): New function. (iso8601-parse-time): Support sub-second ISO8601 times.
-rw-r--r--lisp/calendar/iso8601.el35
-rw-r--r--test/lisp/calendar/iso8601-tests.el38
2 files changed, 48 insertions, 25 deletions
diff --git a/lisp/calendar/iso8601.el b/lisp/calendar/iso8601.el
index f8949914f78..66446dafb96 100644
--- a/lisp/calendar/iso8601.el
+++ b/lisp/calendar/iso8601.el
@@ -112,12 +112,16 @@
112 iso8601--duration-combined-match))) 112 iso8601--duration-combined-match)))
113 113
114(defun iso8601-parse (string) 114(defun iso8601-parse (string)
115 "Parse an ISO 8601 date/time string and return a `decoded-time' structure. 115 "Parse an ISO 8601 date/time string and return a `decode-time' structure.
116 116
117The ISO 8601 date/time strings look like \"2008-03-02T13:47:30\", 117The ISO 8601 date/time strings look like \"2008-03-02T13:47:30\",
118but shorter, incomplete strings like \"2008-03-02\" are valid, as 118but shorter, incomplete strings like \"2008-03-02\" are valid, as
119well as variants like \"2008W32\" (week number) and 119well as variants like \"2008W32\" (week number) and
120\"2008-234\" (ordinal day number)." 120\"2008-234\" (ordinal day number).
121
122The `decode-time' value returned will have the same precision as
123STRING, so if a sub-second STRING is passed in, the `decode-time'
124seconds field will be on the (SECONDS . HZ) format."
121 (if (not (iso8601-valid-p string)) 125 (if (not (iso8601-valid-p string))
122 (signal 'wrong-type-argument string) 126 (signal 'wrong-type-argument string)
123 (let* ((date-string (match-string 1 string)) 127 (let* ((date-string (match-string 1 string))
@@ -138,7 +142,7 @@ well as variants like \"2008W32\" (week number) and
138 date))) 142 date)))
139 143
140(defun iso8601-parse-date (string) 144(defun iso8601-parse-date (string)
141 "Parse STRING (in ISO 8601 format) and return a decoded time value." 145 "Parse STRING (in ISO 8601 format) and return a `decode-time' value."
142 (cond 146 (cond
143 ;; Just a year: [-+]YYYY. 147 ;; Just a year: [-+]YYYY.
144 ((iso8601--match iso8601--year-match string) 148 ((iso8601--match iso8601--year-match string)
@@ -218,7 +222,9 @@ well as variants like \"2008W32\" (week number) and
218 year)))) 222 year))))
219 223
220(defun iso8601-parse-time (string) 224(defun iso8601-parse-time (string)
221 "Parse STRING, which should be an ISO 8601 time string, and return a time value." 225 "Parse STRING, which should be an ISO 8601 time string.
226The return value will be a `decode-time' structure with just the
227hour/minute/seconds/zone fields filled in."
222 (if (not (iso8601--match iso8601--full-time-match string)) 228 (if (not (iso8601--match iso8601--full-time-match string))
223 (signal 'wrong-type-argument string) 229 (signal 'wrong-type-argument string)
224 (let ((time (match-string 1 string)) 230 (let ((time (match-string 1 string))
@@ -230,9 +236,22 @@ well as variants like \"2008W32\" (week number) and
230 (string-to-number (match-string 2 time)))) 236 (string-to-number (match-string 2 time))))
231 (second (and (match-string 3 time) 237 (second (and (match-string 3 time)
232 (string-to-number (match-string 3 time)))) 238 (string-to-number (match-string 3 time))))
233 ;; Hm... 239 (fraction (and (match-string 4 time)
234 (_millisecond (and (match-string 4 time)
235 (string-to-number (match-string 4 time))))) 240 (string-to-number (match-string 4 time)))))
241 (when fraction
242 (cond
243 ;; Sub-second time.
244 (second
245 (let ((digits (1+ (truncate (log fraction 10)))))
246 (setq second (cons (+ (* second (expt 10 digits))
247 fraction)
248 (expt 10 digits)))))
249 ;; Fractional minute.
250 (minute
251 (setq second (iso8601--decimalize fraction 60)))
252 (hour
253 ;; Fractional hour.
254 (setq minute (iso8601--decimalize fraction 60)))))
236 (iso8601--decoded-time :hour hour 255 (iso8601--decoded-time :hour hour
237 :minute (or minute 0) 256 :minute (or minute 0)
238 :second (or second 0) 257 :second (or second 0)
@@ -240,6 +259,10 @@ well as variants like \"2008W32\" (week number) and
240 (* 60 (iso8601-parse-zone 259 (* 60 (iso8601-parse-zone
241 zone))))))))) 260 zone)))))))))
242 261
262(defun iso8601--decimalize (fraction base)
263 (round (* base (/ (float fraction)
264 (expt 10 (1+ (truncate (log fraction 10))))))))
265
243(defun iso8601-parse-zone (string) 266(defun iso8601-parse-zone (string)
244 "Parse STRING, which should be an ISO 8601 time zone. 267 "Parse STRING, which should be an ISO 8601 time zone.
245Return the number of minutes." 268Return the number of minutes."
diff --git a/test/lisp/calendar/iso8601-tests.el b/test/lisp/calendar/iso8601-tests.el
index 8d2aec3de5a..1d44e947a77 100644
--- a/test/lisp/calendar/iso8601-tests.el
+++ b/test/lisp/calendar/iso8601-tests.el
@@ -153,25 +153,25 @@
153 (should (equal (iso8601-parse-time "15") 153 (should (equal (iso8601-parse-time "15")
154 '(0 0 15 nil nil nil nil nil nil)))) 154 '(0 0 15 nil nil nil nil nil nil))))
155 155
156;; Not implemented yet. 156(ert-deftest standard-test-time-of-day-fractions ()
157 157 (should (equal (iso8601-parse-time "152735,5")
158;; (ert-deftest standard-test-time-of-day-fractions () 158 '((355 . 10) 27 15 nil nil nil nil nil nil)))
159;; (should (equal (iso8601-parse-time "152735,5") 159 (should (equal (iso8601-parse-time "15:27:35,5")
160;; '(46 27 15 nil nil nil nil nil nil))) 160 '((355 . 10) 27 15 nil nil nil nil nil nil)))
161;; (should (equal (iso8601-parse-time "15:27:35,5") 161
162;; '(46 27 15 nil nil nil nil nil nil))) 162 (should (equal (iso8601-parse-time "2320,5")
163 163 '(30 20 23 nil nil nil nil nil nil)))
164;; (should (equal (iso8601-parse-time "2320,8") 164 (should (equal (iso8601-parse-time "23:20,8")
165;; '(46 27 15 nil nil nil nil nil nil))) 165 '(48 20 23 nil nil nil nil nil nil)))
166;; (should (equal (iso8601-parse-time "23:20,8") 166
167;; '(46 27 15 nil nil nil nil nil nil))) 167 (should (equal (iso8601-parse-time "23,3")
168 168 '(0 18 23 nil nil nil nil nil nil))))
169;; (should (equal (iso8601-parse-time "23,3") 169
170;; '(46 27 15 nil nil nil nil nil nil)))) 170(ert-deftest nonstandard-test-time-of-day-decimals ()
171 171 (should (equal (iso8601-parse-time "15:27:35.123")
172;; (ert-deftest nonstandard-test-time-of-day-decimals () 172 '((35123 . 1000) 27 15 nil nil nil nil nil nil)))
173;; (should (equal (iso8601-parse-time "15:27:35.123") 173 (should (equal (iso8601-parse-time "15:27:35.123456789")
174;; '(46 27 15 nil nil nil nil nil nil)))) 174 '((35123456789 . 1000000000) 27 15 nil nil nil nil nil nil))))
175 175
176(ert-deftest standard-test-time-of-day-beginning-of-day () 176(ert-deftest standard-test-time-of-day-beginning-of-day ()
177 (should (equal (iso8601-parse-time "000000") 177 (should (equal (iso8601-parse-time "000000")