aboutsummaryrefslogtreecommitdiffstats
path: root/lisp
diff options
context:
space:
mode:
authorPaul Eggert2019-08-16 22:09:04 -0700
committerPaul Eggert2019-08-16 23:25:07 -0700
commit37257d6acadff17bd1e52cfa460950bcb684c5c3 (patch)
treeab7088cfa725561c8456f388cff79466948b3532 /lisp
parentd7c9ed8445d13de7350be3360d68717362f89929 (diff)
downloademacs-37257d6acadff17bd1e52cfa460950bcb684c5c3.tar.gz
emacs-37257d6acadff17bd1e52cfa460950bcb684c5c3.zip
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')
-rw-r--r--lisp/calendar/icalendar.el2
-rw-r--r--lisp/calendar/iso8601.el14
-rw-r--r--lisp/calendar/parse-time.el8
-rw-r--r--lisp/calendar/time-date.el75
-rw-r--r--lisp/net/soap-client.el4
-rw-r--r--lisp/org/org.el4
-rw-r--r--lisp/simple.el8
7 files changed, 41 insertions, 74 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!"
644 ;; create the decoded date-time 644 ;; create the decoded date-time
645 ;; FIXME!?! 645 ;; FIXME!?!
646 (let ((decoded-time (list second minute hour day month year 646 (let ((decoded-time (list second minute hour day month year
647 nil -1 zone 0))) 647 nil -1 zone)))
648 (condition-case nil 648 (condition-case nil
649 (decode-time (encode-time decoded-time)) 649 (decode-time (encode-time decoded-time))
650 (error 650 (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
129 (let ((time (iso8601-parse-time time-string))) 129 (let ((time (iso8601-parse-time time-string)))
130 (setf (decoded-time-hour date) (decoded-time-hour time)) 130 (setf (decoded-time-hour date) (decoded-time-hour time))
131 (setf (decoded-time-minute date) (decoded-time-minute time)) 131 (setf (decoded-time-minute date) (decoded-time-minute time))
132 (setf (decoded-time-second date) (decoded-time-second time)) 132 (setf (decoded-time-second date) (decoded-time-second time))))
133 (setf (decoded-time-subsec date) (decoded-time-subsec time))))
134 ;; The time zone is optional. 133 ;; The time zone is optional.
135 (when zone-string 134 (when zone-string
136 (setf (decoded-time-zone date) 135 (setf (decoded-time-zone date)
@@ -237,8 +236,6 @@ well as variants like \"2008W32\" (week number) and
237 (iso8601--decoded-time :hour hour 236 (iso8601--decoded-time :hour hour
238 :minute (or minute 0) 237 :minute (or minute 0)
239 :second (or second 0) 238 :second (or second 0)
240 ;; FIXME: Support subsec.
241 :subsec 0
242 :zone (and zone 239 :zone (and zone
243 (* 60 (iso8601-parse-zone 240 (* 60 (iso8601-parse-zone
244 zone))))))))) 241 zone)))))))))
@@ -277,9 +274,7 @@ Return the number of minutes."
277 :day (or (match-string 3 string) 0) 274 :day (or (match-string 3 string) 0)
278 :hour (or (match-string 5 string) 0) 275 :hour (or (match-string 5 string) 0)
279 :minute (or (match-string 6 string) 0) 276 :minute (or (match-string 6 string) 0)
280 :second (or (match-string 7 string) 0) 277 :second (or (match-string 7 string) 0)))
281 ;; FIXME: Support subsec.
282 :subsec 0))
283 ;; PnW: Weeks. 278 ;; PnW: Weeks.
284 ((iso8601--match iso8601--duration-week-match string) 279 ((iso8601--match iso8601--duration-week-match string)
285 (let ((weeks (string-to-number (match-string 1 string)))) 280 (let ((weeks (string-to-number (match-string 1 string))))
@@ -341,7 +336,7 @@ Return the number of minutes."
341 336
342(cl-defun iso8601--decoded-time (&key second minute hour 337(cl-defun iso8601--decoded-time (&key second minute hour
343 day month year 338 day month year
344 dst zone subsec) 339 dst zone)
345 (list (iso8601--value second) 340 (list (iso8601--value second)
346 (iso8601--value minute) 341 (iso8601--value minute)
347 (iso8601--value hour) 342 (iso8601--value hour)
@@ -350,8 +345,7 @@ Return the number of minutes."
350 (iso8601--value year) 345 (iso8601--value year)
351 nil 346 nil
352 dst 347 dst
353 zone 348 zone))
354 subsec))
355 349
356(defun iso8601--encode-time (time) 350(defun iso8601--encode-time (time)
357 "Like `encode-time', but fill in nil values in TIME." 351 "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."
148 148
149;;;###autoload 149;;;###autoload
150(defun parse-time-string (string) 150(defun parse-time-string (string)
151 "Parse the time in STRING into (SEC MIN HOUR DAY MON YEAR DOW DST TZ SUBSEC). 151 "Parse the time in STRING into (SEC MIN HOUR DAY MON YEAR DOW DST TZ).
152STRING should be something resembling an RFC 822 (or later) date-time, e.g., 152STRING should be something resembling an RFC 822 (or later) date-time, e.g.,
153\"Fri, 25 Mar 2016 16:24:56 +0100\", but this function is 153\"Fri, 25 Mar 2016 16:24:56 +0100\", but this function is
154somewhat liberal in what format it accepts, and will attempt to 154somewhat liberal in what format it accepts, and will attempt to
@@ -156,7 +156,7 @@ return a \"likely\" value even for somewhat malformed strings.
156The values returned are identical to those of `decode-time', but 156The values returned are identical to those of `decode-time', but
157any unknown values other than DST are returned as nil, and an 157any unknown values other than DST are returned as nil, and an
158unknown DST value is returned as -1." 158unknown DST value is returned as -1."
159 (let ((time (list nil nil nil nil nil nil nil -1 nil nil)) 159 (let ((time (list nil nil nil nil nil nil nil -1 nil))
160 (temp (parse-time-tokenize (downcase string)))) 160 (temp (parse-time-tokenize (downcase string))))
161 (while temp 161 (while temp
162 (let ((parse-time-elt (pop temp)) 162 (let ((parse-time-elt (pop temp))
@@ -193,10 +193,6 @@ unknown DST value is returned as -1."
193 (funcall this))) 193 (funcall this)))
194 parse-time-val))) 194 parse-time-val)))
195 (setf (nth (pop slots) time) new-val)))))))) 195 (setf (nth (pop slots) time) new-val))))))))
196 ;; FIXME: Currently parse-time-string does not parse subseconds.
197 ;; So if seconds were found, set subseconds to zero.
198 (when (nth 0 time)
199 (setf (nth 9 time) 0))
200 time)) 196 time))
201 197
202(defun parse-iso8601-time-string (date-string) 198(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."
420 420
421 ;; Do the time part, which is pretty simple (except for leap 421 ;; Do the time part, which is pretty simple (except for leap
422 ;; seconds, I guess). 422 ;; seconds, I guess).
423 (setq seconds (+ (* (or (decoded-time-hour delta) 0) 3600)
424 (* (or (decoded-time-minute delta) 0) 60)
425 (or (decoded-time-second delta) 0)))
426 (when (decoded-time-subsec delta)
427 (let* ((subsec (time-convert (time-add (decoded-time-subsec time)
428 (decoded-time-subsec delta))
429 t))
430 (s (time-convert subsec 'integer)))
431 (setq seconds (+ seconds s))
432 (setf (decoded-time-subsec time) (time-subtract subsec s))))
433
434 ;; Time zone adjustments are basically the same as time adjustments. 423 ;; Time zone adjustments are basically the same as time adjustments.
435 (setq seconds (+ seconds (or (decoded-time-zone delta) 0))) 424 (setq seconds (time-add (+ (* (or (decoded-time-hour delta) 0) 3600)
436 425 (* (or (decoded-time-minute delta) 0) 60)
437 (cond 426 (or (decoded-time-zone delta) 0))
438 ((> seconds 0) 427 (or (decoded-time-second delta) 0)))
439 (decoded-time--alter-second time seconds t))
440 ((< seconds 0)
441 (decoded-time--alter-second time (abs seconds) nil)))
442 428
429 (decoded-time--alter-second time seconds)
443 time)) 430 time))
444 431
445(defun decoded-time--alter-month (time increase) 432(defun decoded-time--alter-month (time increase)
@@ -472,38 +459,31 @@ changes in daylight saving time are not taken into account."
472 (date-days-in-month (decoded-time-year time) 459 (date-days-in-month (decoded-time-year time)
473 (decoded-time-month time)))))) 460 (decoded-time-month time))))))
474 461
475(defun decoded-time--alter-second (time seconds increase) 462(defun decoded-time--alter-second (time seconds)
476 "Increase or decrease the time in TIME by SECONDS." 463 "Increase the time in TIME by SECONDS."
477 (let ((old (+ (* (or (decoded-time-hour time) 0) 3600) 464 (let* ((secsperday 86400)
478 (* (or (decoded-time-minute time) 0) 60) 465 (old (time-add (+ (* 3600 (or (decoded-time-hour time) 0))
479 (or (decoded-time-second time) 0)))) 466 (* 60 (or (decoded-time-minute time) 0)))
480 467 (or (decoded-time-second time) 0)))
481 (if increase 468 (new (time-add old seconds)))
482 (progn 469 ;; Hm... DST...
483 (setq old (+ old seconds)) 470 (while (time-less-p new 0)
484 (setf (decoded-time-second time) (% old 60) 471 (decoded-time--alter-day time nil)
485 (decoded-time-minute time) (% (/ old 60) 60) 472 (setq new (time-add new secsperday)))
486 (decoded-time-hour time) (% (/ old 3600) 24)) 473 (while (not (time-less-p new secsperday))
487 ;; Hm... DST... 474 (decoded-time--alter-day time t)
488 (let ((days (/ old (* 60 60 24)))) 475 (setq new (time-subtract new secsperday)))
489 (while (> days 0) 476 (let ((sec (time-convert new 'integer)))
490 (decoded-time--alter-day time t) 477 (setf (decoded-time-second time) (time-add (% sec 60)
491 (cl-decf days)))) 478 (time-subtract new sec))
492 (setq old (abs (- old seconds))) 479 (decoded-time-minute time) (% (/ sec 60) 60)
493 (setf (decoded-time-second time) (% old 60) 480 (decoded-time-hour time) (/ sec 3600)))))
494 (decoded-time-minute time) (% (/ old 60) 60)
495 (decoded-time-hour time) (% (/ old 3600) 24))
496 ;; Hm... DST...
497 (let ((days (/ old (* 60 60 24))))
498 (while (> days 0)
499 (decoded-time--alter-day time nil)
500 (cl-decf days))))))
501 481
502(cl-defun make-decoded-time (&key second minute hour 482(cl-defun make-decoded-time (&key second minute hour
503 day month year 483 day month year
504 dst zone subsec) 484 dst zone)
505 "Return a `decoded-time' structure with only the keywords given filled out." 485 "Return a `decoded-time' structure with only the keywords given filled out."
506 (list second minute hour day month year nil dst zone subsec)) 486 (list second minute hour day month year nil dst zone))
507 487
508(defun decoded-time-set-defaults (time &optional default-zone) 488(defun decoded-time-set-defaults (time &optional default-zone)
509 "Set any nil values in `decoded-time' TIME to default values. 489 "Set any nil values in `decoded-time' TIME to default values.
@@ -533,9 +513,6 @@ TIME is modified and returned."
533 (when (and (not (decoded-time-zone time)) 513 (when (and (not (decoded-time-zone time))
534 default-zone) 514 default-zone)
535 (setf (decoded-time-zone time) 0)) 515 (setf (decoded-time-zone time) 0))
536
537 (unless (decoded-time-subsec time)
538 (setf (decoded-time-subsec time) 0))
539 time) 516 time)
540 517
541(provide 'time-date) 518(provide 'time-date)
diff --git a/lisp/net/soap-client.el b/lisp/net/soap-client.el
index eb08511171e..7ce7d79c742 100644
--- a/lisp/net/soap-client.el
+++ b/lisp/net/soap-client.el
@@ -561,8 +561,8 @@ gMonthDay, gDay or gMonth.
561Return a list in a format (SEC MINUTE HOUR DAY MONTH YEAR 561Return a list in a format (SEC MINUTE HOUR DAY MONTH YEAR
562SEC-FRACTION DATATYPE ZONE). This format is meant to be similar 562SEC-FRACTION DATATYPE ZONE). This format is meant to be similar
563to that returned by `decode-time' (and compatible with 563to that returned by `decode-time' (and compatible with
564`encode-time'). The differences are the SUBSEC (fractional 564`encode-time'). The differences are the SEC (seconds)
565seconds) field is omitted, the DOW (day-of-week) field 565field is always an integer, the DOW (day-of-week) field
566is replaced with SEC-FRACTION, a float representing the 566is replaced with SEC-FRACTION, a float representing the
567fractional seconds, and the DST (daylight savings time) field is 567fractional seconds, and the DST (daylight savings time) field is
568replaced with DATATYPE, a symbol representing the XSD primitive 568replaced with DATATYPE, a symbol representing the XSD primitive
diff --git a/lisp/org/org.el b/lisp/org/org.el
index 336c413c8c7..ab29353ae89 100644
--- a/lisp/org/org.el
+++ b/lisp/org/org.el
@@ -17775,12 +17775,14 @@ NODEFAULT, hour and minute fields will be nil if not given."
17775 (string-to-number (match-string 4 s)) 17775 (string-to-number (match-string 4 s))
17776 (string-to-number (match-string 3 s)) 17776 (string-to-number (match-string 3 s))
17777 (string-to-number (match-string 2 s)) 17777 (string-to-number (match-string 2 s))
17778 nil nil nil 0)) 17778 nil nil nil))
17779 ((string-match "^<[^>]+>$" s) 17779 ((string-match "^<[^>]+>$" s)
17780 ;; FIXME: `decode-time' needs to be called with ZONE as its 17780 ;; FIXME: `decode-time' needs to be called with ZONE as its
17781 ;; second argument. However, this requires at least Emacs 17781 ;; second argument. However, this requires at least Emacs
17782 ;; 25.1. We can do it when we switch to this version as our 17782 ;; 25.1. We can do it when we switch to this version as our
17783 ;; minimal requirement. 17783 ;; minimal requirement.
17784 ;; FIXME: decode-time needs to be called with t as its
17785 ;; third argument, but this requires at least Emacs 27.
17784 (decode-time (org-matcher-time s))) 17786 (decode-time (org-matcher-time s)))
17785 (t (error "Not a standard Org time string: %s" s)))) 17787 (t (error "Not a standard Org time string: %s" s))))
17786 17788
diff --git a/lisp/simple.el b/lisp/simple.el
index cb938bb341d..fdf7d893cde 100644
--- a/lisp/simple.el
+++ b/lisp/simple.el
@@ -9082,8 +9082,9 @@ to capitalize ARG words."
9082 (:copier nil) 9082 (:copier nil)
9083 (:type list)) 9083 (:type list))
9084 (second nil :documentation "\ 9084 (second nil :documentation "\
9085This is an integer between 0 and 60 (inclusive). (60 is a leap 9085This is an integer or a Lisp timestamp (TICKS . HZ) representing a nonnegative
9086second, which only some operating systems support.)") 9086number of seconds less than 61. (If not less than 60, it is a leap second,
9087which only some operating systems support.)")
9087 (minute nil :documentation "This is an integer between 0 and 59 (inclusive).") 9088 (minute nil :documentation "This is an integer between 0 and 59 (inclusive).")
9088 (hour nil :documentation "This is an integer between 0 and 23 (inclusive).") 9089 (hour nil :documentation "This is an integer between 0 and 23 (inclusive).")
9089 (day nil :documentation "This is an integer between 1 and 31 (inclusive).") 9090 (day nil :documentation "This is an integer between 1 and 31 (inclusive).")
@@ -9099,9 +9100,6 @@ available.")
9099 (zone nil :documentation "\ 9100 (zone nil :documentation "\
9100This is an integer indicating the UTC offset in seconds, i.e., 9101This is an integer indicating the UTC offset in seconds, i.e.,
9101the number of seconds east of Greenwich.") 9102the number of seconds east of Greenwich.")
9102 (subsec nil :documentation "\
9103This is 0, or is an integer pair (TICKS . HZ) indicating TICKS/HZ seconds,
9104where HZ is positive and TICKS is nonnegative and less than HZ.")
9105 ) 9103 )
9106 9104
9107 9105