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/time-date.el | |
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/time-date.el')
-rw-r--r-- | lisp/calendar/time-date.el | 75 |
1 files changed, 26 insertions, 49 deletions
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) |