emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] master 0df01e3: Add support for sub-second ISO8601 strings


From: Lars Ingebrigtsen
Subject: [Emacs-diffs] master 0df01e3: Add support for sub-second ISO8601 strings
Date: Sun, 29 Sep 2019 15:22:44 -0400 (EDT)

branch: master
commit 0df01e3aa5f8372995bdc39be36c444c54a52f7e
Author: Lars Ingebrigtsen <address@hidden>
Commit: Lars Ingebrigtsen <address@hidden>

    Add support for sub-second ISO8601 strings
    
    * lisp/calendar/iso8601.el (iso8601--decimalize): New function.
    (iso8601-parse-time): Support sub-second ISO8601 times.
---
 lisp/calendar/iso8601.el            | 35 ++++++++++++++++++++++++++++------
 test/lisp/calendar/iso8601-tests.el | 38 ++++++++++++++++++-------------------
 2 files changed, 48 insertions(+), 25 deletions(-)

diff --git a/lisp/calendar/iso8601.el b/lisp/calendar/iso8601.el
index f894991..66446da 100644
--- a/lisp/calendar/iso8601.el
+++ b/lisp/calendar/iso8601.el
@@ -112,12 +112,16 @@
          iso8601--duration-combined-match)))
 
 (defun iso8601-parse (string)
-  "Parse an ISO 8601 date/time string and return a `decoded-time' structure.
+  "Parse an ISO 8601 date/time string and return a `decode-time' structure.
 
 The ISO 8601 date/time strings look like \"2008-03-02T13:47:30\",
 but shorter, incomplete strings like \"2008-03-02\" are valid, as
 well as variants like \"2008W32\" (week number) and
-\"2008-234\" (ordinal day number)."
+\"2008-234\" (ordinal day number).
+
+The `decode-time' value returned will have the same precision as
+STRING, so if a sub-second STRING is passed in, the `decode-time'
+seconds field will be on the (SECONDS . HZ) format."
   (if (not (iso8601-valid-p string))
       (signal 'wrong-type-argument string)
     (let* ((date-string (match-string 1 string))
@@ -138,7 +142,7 @@ well as variants like \"2008W32\" (week number) and
       date)))
 
 (defun iso8601-parse-date (string)
-  "Parse STRING (in ISO 8601 format) and return a decoded time value."
+  "Parse STRING (in ISO 8601 format) and return a `decode-time' value."
   (cond
    ;; Just a year: [-+]YYYY.
    ((iso8601--match iso8601--year-match string)
@@ -218,7 +222,9 @@ well as variants like \"2008W32\" (week number) and
         year))))
 
 (defun iso8601-parse-time (string)
-  "Parse STRING, which should be an ISO 8601 time string, and return a time 
value."
+  "Parse STRING, which should be an ISO 8601 time string.
+The return value will be a `decode-time' structure with just the
+hour/minute/seconds/zone fields filled in."
   (if (not (iso8601--match iso8601--full-time-match string))
       (signal 'wrong-type-argument string)
     (let ((time (match-string 1 string))
@@ -230,9 +236,22 @@ well as variants like \"2008W32\" (week number) and
                            (string-to-number (match-string 2 time))))
               (second (and (match-string 3 time)
                            (string-to-number (match-string 3 time))))
-              ;; Hm...
-              (_millisecond (and (match-string 4 time)
+              (fraction (and (match-string 4 time)
                              (string-to-number (match-string 4 time)))))
+          (when fraction
+            (cond
+             ;; Sub-second time.
+             (second
+              (let ((digits (1+ (truncate (log fraction 10)))))
+                (setq second (cons (+ (* second (expt 10 digits))
+                                      fraction)
+                                   (expt 10 digits)))))
+             ;; Fractional minute.
+             (minute
+              (setq second (iso8601--decimalize fraction 60)))
+             (hour
+              ;; Fractional hour.
+              (setq minute (iso8601--decimalize fraction 60)))))
           (iso8601--decoded-time :hour hour
                                  :minute (or minute 0)
                                  :second (or second 0)
@@ -240,6 +259,10 @@ well as variants like \"2008W32\" (week number) and
                                             (* 60 (iso8601-parse-zone
                                                    zone)))))))))
 
+(defun iso8601--decimalize (fraction base)
+  (round (* base (/ (float fraction)
+                    (expt 10 (1+ (truncate (log fraction 10))))))))
+
 (defun iso8601-parse-zone (string)
   "Parse STRING, which should be an ISO 8601 time zone.
 Return the number of minutes."
diff --git a/test/lisp/calendar/iso8601-tests.el 
b/test/lisp/calendar/iso8601-tests.el
index 8d2aec3..1d44e94 100644
--- a/test/lisp/calendar/iso8601-tests.el
+++ b/test/lisp/calendar/iso8601-tests.el
@@ -153,25 +153,25 @@
   (should (equal (iso8601-parse-time "15")
                  '(0 0 15 nil nil nil nil nil nil))))
 
-;; Not implemented yet.
-
-;; (ert-deftest standard-test-time-of-day-fractions ()
-;;   (should (equal (iso8601-parse-time "152735,5")
-;;                  '(46 27 15 nil nil nil nil nil nil)))
-;;   (should (equal (iso8601-parse-time "15:27:35,5")
-;;                  '(46 27 15 nil nil nil nil nil nil)))
-
-;;   (should (equal (iso8601-parse-time "2320,8")
-;;                  '(46 27 15 nil nil nil nil nil nil)))
-;;   (should (equal (iso8601-parse-time "23:20,8")
-;;                  '(46 27 15 nil nil nil nil nil nil)))
-
-;;   (should (equal (iso8601-parse-time "23,3")
-;;                  '(46 27 15 nil nil nil nil nil nil))))
-
-;; (ert-deftest nonstandard-test-time-of-day-decimals ()
-;;   (should (equal (iso8601-parse-time "15:27:35.123")
-;;                  '(46 27 15 nil nil nil nil nil nil))))
+(ert-deftest standard-test-time-of-day-fractions ()
+  (should (equal (iso8601-parse-time "152735,5")
+                 '((355 . 10) 27 15 nil nil nil nil nil nil)))
+  (should (equal (iso8601-parse-time "15:27:35,5")
+                 '((355 . 10) 27 15 nil nil nil nil nil nil)))
+
+  (should (equal (iso8601-parse-time "2320,5")
+                 '(30 20 23 nil nil nil nil nil nil)))
+  (should (equal (iso8601-parse-time "23:20,8")
+                 '(48 20 23 nil nil nil nil nil nil)))
+
+  (should (equal (iso8601-parse-time "23,3")
+                 '(0 18 23 nil nil nil nil nil nil))))
+
+(ert-deftest nonstandard-test-time-of-day-decimals ()
+  (should (equal (iso8601-parse-time "15:27:35.123")
+                 '((35123 . 1000) 27 15 nil nil nil nil nil nil)))
+  (should (equal (iso8601-parse-time "15:27:35.123456789")
+                 '((35123456789 . 1000000000) 27 15 nil nil nil nil nil nil))))
 
 (ert-deftest standard-test-time-of-day-beginning-of-day ()
   (should (equal (iso8601-parse-time "000000")



reply via email to

[Prev in Thread] Current Thread [Next in Thread]