From 53f7e58a838f766d844a37c10a69d10e758872a6 Mon Sep 17 00:00:00 2001 From: Lars Ingebrigtsen Date: Mon, 8 Jul 2019 20:38:06 +0200 Subject: Start implementing the ISO test corpus --- lisp/calendar/iso8601.el | 54 ++++++++++++++++++++++--------------- test/lisp/calendar/iso8601-tests.el | 37 ++++++++++++++++++++++++- 2 files changed, 68 insertions(+), 23 deletions(-) diff --git a/lisp/calendar/iso8601.el b/lisp/calendar/iso8601.el index e2fddfb8cd9..67c39a0d980 100644 --- a/lisp/calendar/iso8601.el +++ b/lisp/calendar/iso8601.el @@ -44,15 +44,15 @@ (defconst iso8601--year-match "\\([-+]\\)?\\([0-9][0-9][0-9][0-9]\\)") (defconst iso8601--full-date-match - "\\([0-9][0-9][0-9][0-9]\\)-?\\([0-9][0-9]\\)-?\\([0-9][0-9]\\)") + "\\([-+]\\)?\\([0-9][0-9][0-9][0-9]\\)-?\\([0-9][0-9]\\)-?\\([0-9][0-9]\\)") (defconst iso8601--without-day-match - "\\([0-9][0-9][0-9][0-9]\\)-\\([0-9][0-9]\\)") + "\\([-+]\\)?\\([0-9][0-9][0-9][0-9]\\)-\\([0-9][0-9]\\)") (defconst iso8601--outdated-date-match "--\\([0-9][0-9]\\)-?\\([0-9][0-9]\\)") (defconst iso8601--week-date-match - "\\([0-9][0-9][0-9][0-9]\\)-?W\\([0-9][0-9]\\)-?\\([0-9]\\)?") + "\\([-+]\\)?\\([0-9][0-9][0-9][0-9]\\)-?W\\([0-9][0-9]\\)-?\\([0-9]\\)?") (defconst iso8601--ordinal-date-match - "\\([0-9][0-9][0-9][0-9]\\)-?\\([0-9][0-9][0-9]\\)") + "\\([-+]\\)?\\([0-9][0-9][0-9][0-9]\\)-?\\([0-9][0-9][0-9]\\)") (defconst iso8601--date-match (iso8601--concat-regexps (list iso8601--year-match @@ -118,24 +118,22 @@ well as variants like \"2008W32\" (week number) and (cond ;; Just a year: [-+]YYYY. ((iso8601--match iso8601--year-match string) - (let ((year (string-to-number (match-string 2 string))) - (sign (match-string 1 string))) - (iso8601--decoded-time - :year (if (string= sign "-") - ;; -0001 is 2 BCE. - (- year 1) - year)))) + (iso8601--decoded-time + :year (iso8601--adjust-year (match-string 1 string) + (match-string 2 string)))) ;; Calendar dates: YYYY-MM-DD and variants. ((iso8601--match iso8601--full-date-match string) (iso8601--decoded-time - :year (match-string 1 string) - :month (match-string 2 string) - :day (match-string 3 string))) + :year (iso8601--adjust-year (match-string 1 string) + (match-string 2 string)) + :month (match-string 3 string) + :day (match-string 4 string))) ;; Calendar date without day: YYYY-MM. ((iso8601--match iso8601--without-day-match string) (iso8601--decoded-time - :year (match-string 1 string) - :month (match-string 2 string))) + :year (iso8601--adjust-year (match-string 1 string) + (match-string 2 string)) + :month (match-string 3 string))) ;; Outdated date without year: --MM-DD ((iso8601--match iso8601--outdated-date-match string) (iso8601--decoded-time @@ -143,10 +141,11 @@ well as variants like \"2008W32\" (week number) and :day (match-string 2 string))) ;; Week dates: YYYY-Www-D ((iso8601--match iso8601--week-date-match string) - (let* ((year (string-to-number (match-string 1 string))) - (week (string-to-number (match-string 2 string))) - (day-of-week (and (match-string 3 string) - (string-to-number (match-string 3 string)))) + (let* ((year (iso8601--adjust-year (match-string 1 string) + (match-string 2 string))) + (week (string-to-number (match-string 3 string))) + (day-of-week (and (match-string 4 string) + (string-to-number (match-string 4 string)))) (jan-start (decoded-time-weekday (decode-time (encode-time @@ -174,8 +173,9 @@ well as variants like \"2008W32\" (week number) and :day (decoded-time-day month-day))))) ;; Ordinal dates: YYYY-DDD ((iso8601--match iso8601--ordinal-date-match string) - (let* ((year (string-to-number (match-string 1 string))) - (ordinal (string-to-number (match-string 2 string))) + (let* ((year (iso8601--adjust-year (match-string 1 string) + (match-string 2 string))) + (ordinal (string-to-number (match-string 3 string))) (month-day (date-ordinal-to-time year ordinal))) (iso8601--decoded-time :year year :month (decoded-time-month month-day) @@ -183,6 +183,16 @@ well as variants like \"2008W32\" (week number) and (t (signal 'wrong-type-argument string)))) +(defun iso8601--adjust-year (sign year) + (save-match-data + (let ((year (if (stringp year) + (string-to-number year) + year))) + (if (string= sign "-") + ;; -0001 is 2 BCE. + (1- (- year)) + year)))) + (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)) diff --git a/test/lisp/calendar/iso8601-tests.el b/test/lisp/calendar/iso8601-tests.el index 29f599bc338..88d656290aa 100644 --- a/test/lisp/calendar/iso8601-tests.el +++ b/test/lisp/calendar/iso8601-tests.el @@ -26,7 +26,7 @@ (should (equal (iso8601-parse-date "1985") '(0 0 0 1 1 1985 nil nil nil))) (should (equal (iso8601-parse-date "-0003") - '(0 0 0 1 1 2 nil nil nil))) + '(0 0 0 1 1 -4 nil nil nil))) (should (equal (iso8601-parse-date "+1985") '(0 0 0 1 1 1985 nil nil nil)))) @@ -107,4 +107,39 @@ (0 30 15 11 5 2008 nil nil 0) (0 30 2 10 2 1 nil nil nil))))) +(ert-deftest standard-test-dates () + (should (equal (iso8601-parse-date "19850412") + '(0 0 0 12 4 1985 nil nil nil))) + (should (equal (iso8601-parse-date "1985-04-12") + '(0 0 0 12 4 1985 nil nil nil))) + + (should (equal (iso8601-parse-date "1985102") + '(0 0 0 12 4 1985 nil nil nil))) + (should (equal (iso8601-parse-date "1985-102") + '(0 0 0 12 4 1985 nil nil nil))) + + (should (equal (iso8601-parse-date "1985W155") + '(0 0 0 12 4 1985 nil nil nil))) + (should (equal (iso8601-parse-date "1985-W15-5") + '(0 0 0 12 4 1985 nil nil nil))) + + (should (equal (iso8601-parse-date "1985W15") + '(0 0 0 7 4 1985 nil nil nil))) + (should (equal (iso8601-parse-date "1985-W15") + '(0 0 0 7 4 1985 nil nil nil))) + + (should (equal (iso8601-parse-date "1985-04") + '(0 0 0 1 4 1985 nil nil nil))) + + (should (equal (iso8601-parse-date "1985") + '(0 0 0 1 1 1985 nil nil nil))) + + (should (equal (iso8601-parse-date "+1985-04-12") + '(0 0 0 12 4 1985 nil nil nil))) + (should (equal (iso8601-parse-date "+19850412") + '(0 0 0 12 4 1985 nil nil nil))) + + ) + + ;;; iso8601-tests.el ends here -- cgit v1.2.1