From 57ca5db4c2dfceef28f0cb9f1398f4752ffaae51 Mon Sep 17 00:00:00 2001 From: Lars Ingebrigtsen Date: Mon, 29 Jul 2019 12:07:44 +0200 Subject: Add support for times with time zones --- lisp/calendar/iso8601.el | 44 +++++++++++++++++----------- test/lisp/calendar/iso8601-tests.el | 57 ++++++++++++++++++++++++++++++++++++- 2 files changed, 83 insertions(+), 18 deletions(-) diff --git a/lisp/calendar/iso8601.el b/lisp/calendar/iso8601.el index 5952586cc86..83b57a4f56a 100644 --- a/lisp/calendar/iso8601.el +++ b/lisp/calendar/iso8601.el @@ -56,11 +56,11 @@ (defconst iso8601--date-match (iso8601--concat-regexps (list iso8601--year-match - iso8601--full-date-match - iso8601--without-day-match - iso8601--outdated-date-match - iso8601--week-date-match - iso8601--ordinal-date-match))) + iso8601--full-date-match + iso8601--without-day-match + iso8601--outdated-date-match + iso8601--week-date-match + iso8601--ordinal-date-match))) (defconst iso8601--time-match "\\([0-9][0-9]\\):?\\([0-9][0-9]\\)?:?\\([0-9][0-9]\\)?\\.?\\([0-9][0-9][0-9]\\)?") @@ -68,6 +68,10 @@ (defconst iso8601--zone-match "\\(Z\\|\\([-+]\\)?\\([0-9][0-9]\\):?\\([0-9][0-9]\\)?\\)") +(defconst iso8601--full-time-match + (concat "\\(" (replace-regexp-in-string "(" "(?:" iso8601--time-match) "\\)" + "\\(" iso8601--zone-match "\\)?")) + (defconst iso8601--combined-match (concat "\\(" iso8601--date-match "\\)" "\\(?:T\\(" @@ -195,19 +199,25 @@ well as variants like \"2008W32\" (week number) and (defun iso8601-parse-time (string) "Parse STRING, which should be an ISO 8601 time string, and return a time value." - (if (not (iso8601--match iso8601--time-match string)) + (if (not (iso8601--match iso8601--full-time-match string)) (signal 'wrong-type-argument string) - (let ((hour (string-to-number (match-string 1 string))) - (minute (and (match-string 2 string) - (string-to-number (match-string 2 string)))) - (second (and (match-string 3 string) - (string-to-number (match-string 3 string)))) - ;; Hm... - (_millisecond (and (match-string 4 string) - (string-to-number (match-string 4 string))))) - (iso8601--decoded-time :hour hour - :minute (or minute 0) - :second (or second 0))))) + (let ((time (match-string 1 string)) + (zone (match-string 2 string))) + (if (not (iso8601--match iso8601--time-match time)) + (signal 'wrong-type-argument string) + (let ((hour (string-to-number (match-string 1 time))) + (minute (and (match-string 2 time) + (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) + (string-to-number (match-string 4 time))))) + (iso8601--decoded-time :hour hour + :minute (or minute 0) + :second (or second 0) + :zone (and zone + (iso8601-parse-zone zone)))))))) (defun iso8601-parse-zone (string) "Parse STRING, which should be an ISO 8601 time zone. diff --git a/test/lisp/calendar/iso8601-tests.el b/test/lisp/calendar/iso8601-tests.el index 8517e7dde5d..5403c8e2077 100644 --- a/test/lisp/calendar/iso8601-tests.el +++ b/test/lisp/calendar/iso8601-tests.el @@ -139,7 +139,7 @@ (should (equal (iso8601-parse-date "+19850412") '(nil nil nil 12 4 1985 nil nil nil)))) -(ert-deftest standard-test-time-of-day () +(ert-deftest standard-test-time-of-day-local-time () (should (equal (iso8601-parse-time "152746") '(46 27 15 nil nil nil nil nil nil))) (should (equal (iso8601-parse-time "15:27:46") @@ -153,4 +153,59 @@ (should (equal (iso8601-parse-time "15") '(0 0 15 nil nil nil nil nil nil)))) +(ert-deftest standard-test-time-of-day-fractions () + ;; decoded-time doesn't support sub-second times. + ;; (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))) + ) + +(ert-deftest standard-test-time-of-day-beginning-of-day () + (should (equal (iso8601-parse-time "000000") + '(0 0 0 nil nil nil nil nil nil))) + (should (equal (iso8601-parse-time "00:00:00") + '(0 0 0 nil nil nil nil nil nil))) + + (should (equal (iso8601-parse-time "0000") + '(0 0 0 nil nil nil nil nil nil))) + (should (equal (iso8601-parse-time "00:00") + '(0 0 0 nil nil nil nil nil nil)))) + +(ert-deftest standard-test-time-of-day-utc () + (should (equal (iso8601-parse-time "232030Z") + '(30 20 23 nil nil nil nil nil 0))) + (should (equal (iso8601-parse-time "23:20:30Z") + '(30 20 23 nil nil nil nil nil 0))) + + (should (equal (iso8601-parse-time "2320Z") + '(0 20 23 nil nil nil nil nil 0))) + (should (equal (iso8601-parse-time "23:20Z") + '(0 20 23 nil nil nil nil nil 0))) + + (should (equal (iso8601-parse-time "23Z") + '(0 0 23 nil nil nil nil nil 0)))) + + +(ert-deftest standard-test-time-of-day-zone () + (should (equal (iso8601-parse-time "152746+0100") + '(46 27 15 nil nil nil nil nil 60))) + (should (equal (iso8601-parse-time "15:27:46+0100") + '(46 27 15 nil nil nil nil nil 60))) + + (should (equal (iso8601-parse-time "152746+01") + '(46 27 15 nil nil nil nil nil 60))) + (should (equal (iso8601-parse-time "15:27:46+01") + '(46 27 15 nil nil nil nil nil 60))) + + (should (equal (iso8601-parse-time "152746-0500") + '(46 27 15 nil nil nil nil nil -300))) + (should (equal (iso8601-parse-time "15:27:46-0500") + '(46 27 15 nil nil nil nil nil -300))) + + (should (equal (iso8601-parse-time "152746-05") + '(46 27 15 nil nil nil nil nil -300))) + (should (equal (iso8601-parse-time "15:27:46-05") + '(46 27 15 nil nil nil nil nil -300)))) + ;;; iso8601-tests.el ends here -- cgit v1.2.1