diff options
author | Paul Eggert <eggert@cs.ucla.edu> | 2019-08-16 22:09:04 -0700 |
---|---|---|
committer | Paul Eggert <eggert@cs.ucla.edu> | 2019-08-16 23:25:07 -0700 |
commit | 37257d6acadff17bd1e52cfa460950bcb684c5c3 (patch) | |
tree | ab7088cfa725561c8456f388cff79466948b3532 /lisp/calendar | |
parent | d7c9ed8445d13de7350be3360d68717362f89929 (diff) | |
download | emacs-37257d6acadff17bd1e52cfa460950bcb684c5c3.tar.gz |
More-compatible subsecond calendrical timestamps
Instead of appending a subseconds member to the result of
‘decode-time’, this keeps the format unchanged unless you give
a new optional argument to ‘decode-time’. Also, the augmented
format now puts the subsecond info in the SECONDS element, so
the total number of elements is unchanged; this is more
compatible with code that expects the traditional 9 elements,
such as ‘(pcase decoded-time (`(,SEC ,MIN ,HOUR ,DAY ,MON
,YEAR ,DOW ,DST ,ZONE) ...) ...)’.
* doc/lispref/os.texi, doc/misc/emacs-mime.texi, etc/NEWS:
* lisp/net/soap-client.el (soap-decode-date-time):
* lisp/simple.el (decoded-time):
Document the new behavior.
* lisp/calendar/icalendar.el (icalendar--decode-isodatetime):
* lisp/calendar/iso8601.el (iso8601-parse)
(iso8601-parse-time, iso8601-parse-duration)
(iso8601--decoded-time):
* lisp/calendar/parse-time.el (parse-time-string):
* lisp/calendar/time-date.el (decoded-time-add)
(decoded-time--alter-second):
* lisp/org/org.el (org-parse-time-string):
* lisp/simple.el (decoded-time):
* src/timefns.c (Fdecode_time, Fencode_time):
* test/lisp/calendar/icalendar-tests.el:
(icalendar--decode-isodatetime):
* test/lisp/calendar/iso8601-tests.el (test-iso8601-date-years)
(test-iso8601-date-dates, test-iso8601-date-obsolete)
(test-iso8601-date-weeks, test-iso8601-date-ordinals)
(test-iso8601-time, test-iso8601-combined)
(test-iso8601-duration, test-iso8601-intervals)
(standard-test-dates, standard-test-time-of-day-fractions)
(standard-test-time-of-day-beginning-of-day)
(standard-test-time-of-day-utc)
(standard-test-time-of-day-zone)
(standard-test-date-and-time-of-day, standard-test-interval):
* test/lisp/calendar/parse-time-tests.el (parse-time-tests):
* test/src/timefns-tests.el (format-time-string-with-zone)
(encode-time-dst-numeric-zone):
Revert recent changes that added a SUBSECS member to
calendrical timestamps, since that component is no longer
present (the info, if any, is now in the SECONDS member).
* lisp/calendar/time-date.el (decoded-time-add)
(decoded-time--alter-second):
Support fractional seconds in the new form. Simplify.
* src/timefns.c (Fdecode_time): Support new arg FORM.
(Fencode_time): Support subsecond resolution.
* test/src/timefns-tests.el (format-time-string-with-zone)
(decode-then-encode-time): Test subsecond calendrical timestamps.
Diffstat (limited to 'lisp/calendar')
-rw-r--r-- | lisp/calendar/icalendar.el | 2 | ||||
-rw-r--r-- | lisp/calendar/iso8601.el | 14 | ||||
-rw-r--r-- | lisp/calendar/parse-time.el | 8 | ||||
-rw-r--r-- | lisp/calendar/time-date.el | 75 |
4 files changed, 33 insertions, 66 deletions
diff --git a/lisp/calendar/icalendar.el b/lisp/calendar/icalendar.el index 84f579ad44e..c2688705e30 100644 --- a/lisp/calendar/icalendar.el +++ b/lisp/calendar/icalendar.el @@ -644,7 +644,7 @@ FIXME: multiple comma-separated values should be allowed!" ;; create the decoded date-time ;; FIXME!?! (let ((decoded-time (list second minute hour day month year - nil -1 zone 0))) + nil -1 zone))) (condition-case nil (decode-time (encode-time decoded-time)) (error diff --git a/lisp/calendar/iso8601.el b/lisp/calendar/iso8601.el index 51f5dff9091..30352c7e75f 100644 --- a/lisp/calendar/iso8601.el +++ b/lisp/calendar/iso8601.el @@ -129,8 +129,7 @@ well as variants like \"2008W32\" (week number) and (let ((time (iso8601-parse-time time-string))) (setf (decoded-time-hour date) (decoded-time-hour time)) (setf (decoded-time-minute date) (decoded-time-minute time)) - (setf (decoded-time-second date) (decoded-time-second time)) - (setf (decoded-time-subsec date) (decoded-time-subsec time)))) + (setf (decoded-time-second date) (decoded-time-second time)))) ;; The time zone is optional. (when zone-string (setf (decoded-time-zone date) @@ -237,8 +236,6 @@ well as variants like \"2008W32\" (week number) and (iso8601--decoded-time :hour hour :minute (or minute 0) :second (or second 0) - ;; FIXME: Support subsec. - :subsec 0 :zone (and zone (* 60 (iso8601-parse-zone zone))))))))) @@ -277,9 +274,7 @@ Return the number of minutes." :day (or (match-string 3 string) 0) :hour (or (match-string 5 string) 0) :minute (or (match-string 6 string) 0) - :second (or (match-string 7 string) 0) - ;; FIXME: Support subsec. - :subsec 0)) + :second (or (match-string 7 string) 0))) ;; PnW: Weeks. ((iso8601--match iso8601--duration-week-match string) (let ((weeks (string-to-number (match-string 1 string)))) @@ -341,7 +336,7 @@ Return the number of minutes." (cl-defun iso8601--decoded-time (&key second minute hour day month year - dst zone subsec) + dst zone) (list (iso8601--value second) (iso8601--value minute) (iso8601--value hour) @@ -350,8 +345,7 @@ Return the number of minutes." (iso8601--value year) nil dst - zone - subsec)) + zone)) (defun iso8601--encode-time (time) "Like `encode-time', but fill in nil values in TIME." diff --git a/lisp/calendar/parse-time.el b/lisp/calendar/parse-time.el index 9af93b5b1ee..b0b277db77d 100644 --- a/lisp/calendar/parse-time.el +++ b/lisp/calendar/parse-time.el @@ -148,7 +148,7 @@ letters, digits, plus or minus signs or colons." ;;;###autoload (defun parse-time-string (string) - "Parse the time in STRING into (SEC MIN HOUR DAY MON YEAR DOW DST TZ SUBSEC). + "Parse the time in STRING into (SEC MIN HOUR DAY MON YEAR DOW DST TZ). STRING should be something resembling an RFC 822 (or later) date-time, e.g., \"Fri, 25 Mar 2016 16:24:56 +0100\", but this function is somewhat liberal in what format it accepts, and will attempt to @@ -156,7 +156,7 @@ return a \"likely\" value even for somewhat malformed strings. The values returned are identical to those of `decode-time', but any unknown values other than DST are returned as nil, and an unknown DST value is returned as -1." - (let ((time (list nil nil nil nil nil nil nil -1 nil nil)) + (let ((time (list nil nil nil nil nil nil nil -1 nil)) (temp (parse-time-tokenize (downcase string)))) (while temp (let ((parse-time-elt (pop temp)) @@ -193,10 +193,6 @@ unknown DST value is returned as -1." (funcall this))) parse-time-val))) (setf (nth (pop slots) time) new-val)))))))) - ;; FIXME: Currently parse-time-string does not parse subseconds. - ;; So if seconds were found, set subseconds to zero. - (when (nth 0 time) - (setf (nth 9 time) 0)) time)) (defun parse-iso8601-time-string (date-string) diff --git a/lisp/calendar/time-date.el b/lisp/calendar/time-date.el index fa5e886869a..f3d252f03c6 100644 --- a/lisp/calendar/time-date.el +++ b/lisp/calendar/time-date.el @@ -420,26 +420,13 @@ changes in daylight saving time are not taken into account." ;; Do the time part, which is pretty simple (except for leap ;; seconds, I guess). - (setq seconds (+ (* (or (decoded-time-hour delta) 0) 3600) - (* (or (decoded-time-minute delta) 0) 60) - (or (decoded-time-second delta) 0))) - (when (decoded-time-subsec delta) - (let* ((subsec (time-convert (time-add (decoded-time-subsec time) - (decoded-time-subsec delta)) - t)) - (s (time-convert subsec 'integer))) - (setq seconds (+ seconds s)) - (setf (decoded-time-subsec time) (time-subtract subsec s)))) - ;; Time zone adjustments are basically the same as time adjustments. - (setq seconds (+ seconds (or (decoded-time-zone delta) 0))) - - (cond - ((> seconds 0) - (decoded-time--alter-second time seconds t)) - ((< seconds 0) - (decoded-time--alter-second time (abs seconds) nil))) + (setq seconds (time-add (+ (* (or (decoded-time-hour delta) 0) 3600) + (* (or (decoded-time-minute delta) 0) 60) + (or (decoded-time-zone delta) 0)) + (or (decoded-time-second delta) 0))) + (decoded-time--alter-second time seconds) time)) (defun decoded-time--alter-month (time increase) @@ -472,38 +459,31 @@ changes in daylight saving time are not taken into account." (date-days-in-month (decoded-time-year time) (decoded-time-month time)))))) -(defun decoded-time--alter-second (time seconds increase) - "Increase or decrease the time in TIME by SECONDS." - (let ((old (+ (* (or (decoded-time-hour time) 0) 3600) - (* (or (decoded-time-minute time) 0) 60) - (or (decoded-time-second time) 0)))) - - (if increase - (progn - (setq old (+ old seconds)) - (setf (decoded-time-second time) (% old 60) - (decoded-time-minute time) (% (/ old 60) 60) - (decoded-time-hour time) (% (/ old 3600) 24)) - ;; Hm... DST... - (let ((days (/ old (* 60 60 24)))) - (while (> days 0) - (decoded-time--alter-day time t) - (cl-decf days)))) - (setq old (abs (- old seconds))) - (setf (decoded-time-second time) (% old 60) - (decoded-time-minute time) (% (/ old 60) 60) - (decoded-time-hour time) (% (/ old 3600) 24)) - ;; Hm... DST... - (let ((days (/ old (* 60 60 24)))) - (while (> days 0) - (decoded-time--alter-day time nil) - (cl-decf days)))))) +(defun decoded-time--alter-second (time seconds) + "Increase the time in TIME by SECONDS." + (let* ((secsperday 86400) + (old (time-add (+ (* 3600 (or (decoded-time-hour time) 0)) + (* 60 (or (decoded-time-minute time) 0))) + (or (decoded-time-second time) 0))) + (new (time-add old seconds))) + ;; Hm... DST... + (while (time-less-p new 0) + (decoded-time--alter-day time nil) + (setq new (time-add new secsperday))) + (while (not (time-less-p new secsperday)) + (decoded-time--alter-day time t) + (setq new (time-subtract new secsperday))) + (let ((sec (time-convert new 'integer))) + (setf (decoded-time-second time) (time-add (% sec 60) + (time-subtract new sec)) + (decoded-time-minute time) (% (/ sec 60) 60) + (decoded-time-hour time) (/ sec 3600))))) (cl-defun make-decoded-time (&key second minute hour day month year - dst zone subsec) + dst zone) "Return a `decoded-time' structure with only the keywords given filled out." - (list second minute hour day month year nil dst zone subsec)) + (list second minute hour day month year nil dst zone)) (defun decoded-time-set-defaults (time &optional default-zone) "Set any nil values in `decoded-time' TIME to default values. @@ -533,9 +513,6 @@ TIME is modified and returned." (when (and (not (decoded-time-zone time)) default-zone) (setf (decoded-time-zone time) 0)) - - (unless (decoded-time-subsec time) - (setf (decoded-time-subsec time) 0)) time) (provide 'time-date) |