aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Eggert2019-08-16 22:09:04 -0700
committerPaul Eggert2019-08-16 23:25:07 -0700
commit37257d6acadff17bd1e52cfa460950bcb684c5c3 (patch)
treeab7088cfa725561c8456f388cff79466948b3532
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.
-rw-r--r--doc/lispref/os.texi65
-rw-r--r--doc/misc/emacs-mime.texi2
-rw-r--r--etc/NEWS22
-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
-rw-r--r--src/timefns.c178
-rw-r--r--test/lisp/calendar/icalendar-tests.el8
-rw-r--r--test/lisp/calendar/iso8601-tests.el190
-rw-r--r--test/lisp/calendar/parse-time-tests.el18
-rw-r--r--test/src/timefns-tests.el46
15 files changed, 337 insertions, 307 deletions
diff --git a/doc/lispref/os.texi b/doc/lispref/os.texi
index 70ae39e6ab6..49c07380c5f 100644
--- a/doc/lispref/os.texi
+++ b/doc/lispref/os.texi
@@ -1478,23 +1478,23 @@ Although @code{(time-convert nil nil)} is equivalent to
1478@end example 1478@end example
1479@end defun 1479@end defun
1480 1480
1481@defun decode-time &optional time zone 1481@defun decode-time &optional time zone form
1482This function converts a time value into calendrical information. If 1482This function converts a time value into calendrical information. If
1483you don't specify @var{time}, it decodes the current time, and similarly 1483you don't specify @var{time}, it decodes the current time, and similarly
1484@var{zone} defaults to the current time zone rule. @xref{Time Zone Rules}. 1484@var{zone} defaults to the current time zone rule. @xref{Time Zone Rules}.
1485The return value is a list of ten elements, as follows: 1485The @var{form} argument controls the form of the returned
1486@var{seconds} element, as described below.
1487The return value is a list of nine elements, as follows:
1486 1488
1487@example 1489@example
1488(@var{seconds} @var{minutes} @var{hour} @var{day} @var{month} @var{year} 1490(@var{seconds} @var{minutes} @var{hour} @var{day} @var{month} @var{year} @var{dow} @var{dst} @var{utcoff})
1489 @var{dow} @var{dst} @var{utcoff} @var{subsec})
1490@end example 1491@end example
1491 1492
1492Here is what the elements mean: 1493Here is what the elements mean:
1493 1494
1494@table @var 1495@table @var
1495@item seconds 1496@item seconds
1496The number of seconds past the minute, as an integer between 0 and 59. 1497The number of seconds past the minute, with form described below.
1497On some operating systems, this is 60 for leap seconds.
1498@item minutes 1498@item minutes
1499The number of minutes past the hour, as an integer between 0 and 59. 1499The number of minutes past the hour, as an integer between 0 and 59.
1500@item hour 1500@item hour
@@ -1514,22 +1514,33 @@ in effect, and @minus{}1 if this information is not available.
1514@item utcoff 1514@item utcoff
1515An integer indicating the Universal Time offset in seconds, i.e., the number of 1515An integer indicating the Universal Time offset in seconds, i.e., the number of
1516seconds east of Greenwich. 1516seconds east of Greenwich.
1517@item subsec
1518The number of subseconds past the second, as either 0 or a Lisp
1519timestamp @code{(@var{ticks} . @var{hz})} representing a nonnegative
1520fraction less than 1.
1521@end table 1517@end table
1522 1518
1519The @var{seconds} element is a Lisp timestamp that is nonnegative and
1520less than 61; it is less than 60 except during positive leap seconds
1521(assuming the operating system supports leap seconds). If the
1522optional @var{form} argument is @code{t}, @var{seconds} uses the same
1523precision as @var{time}; if @var{form} is @code{integer},
1524@var{seconds} is truncated to an integer. For example, if @var{time}
1525is the timestamp @code{(1566009571321 . 1000)}, which represents
15262019-08-17 02:39:31.321 UTC on typical systems that lack leap seconds,
1527then @code{(decode-time @var{time} t t)} returns @code{((31321 . 1000)
152839 2 17 8 2019 6 nil 0)}, whereas @code{(decode-time @var{time} t
1529'integer)} returns @code{(31 39 2 17 8 2019 6 nil 0)}. If @var{form}
1530is omitted or @code{nil}, it currently defaults to @code{integer} but
1531this default may change in future Emacs releases, so callers requiring
1532a particular form should specify @var{form}.
1533
1523@strong{Common Lisp Note:} Common Lisp has different meanings for 1534@strong{Common Lisp Note:} Common Lisp has different meanings for
1524@var{dow} and @var{utcoff}, and lacks @var{subsec}. 1535@var{dow} and @var{utcoff}, and its @var{second} is an integer between
15360 and 59 inclusive.
1525 1537
1526To access (or alter) the elements in the time value, the 1538To access (or alter) the elements in the time value, the
1527@code{decoded-time-second}, @code{decoded-time-minute}, 1539@code{decoded-time-second}, @code{decoded-time-minute},
1528@code{decoded-time-hour}, @code{decoded-time-day}, 1540@code{decoded-time-hour}, @code{decoded-time-day},
1529@code{decoded-time-month}, @code{decoded-time-year}, 1541@code{decoded-time-month}, @code{decoded-time-year},
1530@code{decoded-time-weekday}, @code{decoded-time-dst}, 1542@code{decoded-time-weekday}, @code{decoded-time-dst} and
1531@code{decoded-time-zone} and @code{decoded-time-subsec} 1543@code{decoded-time-zone} accessors can be used.
1532accessors can be used.
1533 1544
1534For instance, to increase the year in a decoded time, you could say: 1545For instance, to increase the year in a decoded time, you could say:
1535 1546
@@ -1551,7 +1562,7 @@ For instance, if you want ``same time next month'', you
1551could say: 1562could say:
1552 1563
1553@lisp 1564@lisp
1554(let ((time (decode-time)) 1565(let ((time (decode-time nil nil t))
1555 (delta (make-decoded-time :month 2))) 1566 (delta (make-decoded-time :month 2)))
1556 (encode-time (decoded-time-add time delta))) 1567 (encode-time (decoded-time-add time delta)))
1557@end lisp 1568@end lisp
@@ -1585,22 +1596,21 @@ It can act as the inverse of @code{decode-time}.
1585 1596
1586Ordinarily the first argument is a list 1597Ordinarily the first argument is a list
1587@code{(@var{second} @var{minute} @var{hour} @var{day} @var{month} 1598@code{(@var{second} @var{minute} @var{hour} @var{day} @var{month}
1588@var{year} @var{ignored} @var{dst} @var{zone} @var{subsec})} that specifies a 1599@var{year} @var{ignored} @var{dst} @var{zone})} that specifies a
1589decoded time in the style of @code{decode-time}, so that 1600decoded time in the style of @code{decode-time}, so that
1590@code{(encode-time (decode-time ...))} works. For the meanings of 1601@code{(encode-time (decode-time ...))} works. For the meanings of
1591these list members, see the table under @code{decode-time}. 1602these list members, see the table under @code{decode-time}.
1592 1603
1593As an obsolescent calling convention, this function can be given six 1604As an obsolescent calling convention, this function can be given six
1594through ten arguments. The first six arguments @var{second}, 1605or more arguments. The first six arguments @var{second},
1595@var{minute}, @var{hour}, @var{day}, @var{month}, and @var{year} 1606@var{minute}, @var{hour}, @var{day}, @var{month}, and @var{year}
1596specify most of the components of a decoded time. If there are seven 1607specify most of the components of a decoded time. If there are more
1597through nine arguments the @emph{last} argument is used as @var{zone}, 1608than six arguments the @emph{last} argument is used as @var{zone} and
1598and if there are ten arguments the ninth specifies @var{zone} and the 1609any other extra arguments are ignored, so that @code{(apply
1599tenth specifies @var{subsec}; in either case any other extra arguments 1610#'encode-time (decode-time ...))} works. In this obsolescent
1600are ignored, so that @code{(apply #'encode-time (decode-time ...))} 1611convention, @var{zone} defaults to the current time zone rule
1601works. In this obsolescent convention, @var{zone} defaults to the 1612(@pxref{Time Zone Rules}), and @var{dst} is treated as if it was
1602current time zone rule (@pxref{Time Zone Rules}), @var{subsec} 1613@minus{}1.
1603defaults to 0, and @var{dst} is treated as if it was @minus{}1.
1604 1614
1605Year numbers less than 100 are not treated specially. If you want them 1615Year numbers less than 100 are not treated specially. If you want them
1606to stand for years above 1900, or years above 2000, you must alter them 1616to stand for years above 1900, or years above 2000, you must alter them
@@ -1615,9 +1625,8 @@ the latter to the former as follows:
1615@end example 1625@end example
1616 1626
1617You can perform simple date arithmetic by using out-of-range values for 1627You can perform simple date arithmetic by using out-of-range values for
1618@var{seconds}, @var{minutes}, @var{hour}, @var{day}, @var{month}, and 1628@var{seconds}, @var{minutes}, @var{hour}, @var{day}, and @var{month};
1619@var{subsec}; for example, day 0 means the day preceding the given 1629for example, day 0 means the day preceding the given month.
1620month.
1621 1630
1622The operating system puts limits on the range of possible time values; 1631The operating system puts limits on the range of possible time values;
1623if the limits are exceeded while encoding the time, an error results. 1632if the limits are exceeded while encoding the time, an error results.
diff --git a/doc/misc/emacs-mime.texi b/doc/misc/emacs-mime.texi
index c411bf3d681..eb829b06124 100644
--- a/doc/misc/emacs-mime.texi
+++ b/doc/misc/emacs-mime.texi
@@ -1535,7 +1535,7 @@ Here's a bunch of time/date/second/day examples:
1535 1535
1536@example 1536@example
1537(parse-time-string "Sat Sep 12 12:21:54 1998 +0200") 1537(parse-time-string "Sat Sep 12 12:21:54 1998 +0200")
1538@result{} (54 21 12 12 9 1998 6 -1 7200 0) 1538@result{} (54 21 12 12 9 1998 6 -1 7200)
1539 1539
1540(time-convert 1540(time-convert
1541 (date-to-time "Sat Sep 12 12:21:54 1998 +0200") 1541 (date-to-time "Sat Sep 12 12:21:54 1998 +0200")
diff --git a/etc/NEWS b/etc/NEWS
index edce7b3e57d..53408a871e7 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -2116,10 +2116,20 @@ probing the innards of a timestamp directly, or creating a timestamp
2116by hand. 2116by hand.
2117 2117
2118+++ 2118+++
2119*** Decoded (calendrical) timestamps now have a new subsecond member. 2119*** Decoded (calendrical) timestamps now have subsecond resolution.
2120This affects functions like decode-time and parse-time-string that 2120This affects decode-time, which generates these timestamps, as well as
2121generate these timestamps, and functions like encode-time that accept 2121functions like encode-time that accept them. The subsecond info is
2122them. 2122present as a (TICKS . HZ) value in the seconds element of a decoded
2123timestamp, and decode-time has a new optional FORM argument specifying
2124the form of the seconds member. For example, if X is the timestamp
2125(1566009571321878186 . 1000000000), which represents 2019-08-17
212602:39:31.321878186 UTC, (decode-time X t t) returns ((31321878186
2127. 1000000000) 39 2 17 8 2019 6 nil 0) instead of the traditional (31
212839 2 17 8 2019 6 nil 0) returned by plain (decode-time X t). Although
2129the default FORM is currently 'integer', which truncates the seconds
2130to an integer and is the traditional behavior, this default may change
2131in future Emacs versions, so callers requiring an integer should
2132specify FORM explicitly.
2123 2133
2124+++ 2134+++
2125*** 'encode-time' supports a new API '(encode-time TIME)'. 2135*** 'encode-time' supports a new API '(encode-time TIME)'.
@@ -2152,8 +2162,8 @@ with POSIX.1-2017.
2152*** To access (or alter) the elements a decoded time value, the 2162*** To access (or alter) the elements a decoded time value, the
2153'decoded-time-second', 'decoded-time-minute', 'decoded-time-hour', 2163'decoded-time-second', 'decoded-time-minute', 'decoded-time-hour',
2154'decoded-time-day', 'decoded-time-month', 'decoded-time-year', 2164'decoded-time-day', 'decoded-time-month', 'decoded-time-year',
2155'decoded-time-weekday', 'decoded-time-dst', 'decoded-time-zone', 2165'decoded-time-weekday', 'decoded-time-dst' and 'decoded-time-zone'
2156and 'decoded-time-subsec' accessors can be used. 2166accessors can be used.
2157 2167
2158*** The new functions 'date-days-in-month' (which will say how many 2168*** The new functions 'date-days-in-month' (which will say how many
2159days there are in a month in a specific year), 'date-ordinal-to-time' 2169days there are in a month in a specific year), 'date-ordinal-to-time'
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
diff --git a/src/timefns.c b/src/timefns.c
index 979550c8431..16c39c83493 100644
--- a/src/timefns.c
+++ b/src/timefns.c
@@ -1374,8 +1374,8 @@ usage: (format-time-string FORMAT-STRING &optional TIME ZONE) */)
1374 t, zone, &tm); 1374 t, zone, &tm);
1375} 1375}
1376 1376
1377DEFUN ("decode-time", Fdecode_time, Sdecode_time, 0, 2, 0, 1377DEFUN ("decode-time", Fdecode_time, Sdecode_time, 0, 3, 0,
1378 doc: /* Decode a time value as (SEC MINUTE HOUR DAY MONTH YEAR DOW DST UTCOFF SUBSEC). 1378 doc: /* Decode a time value as (SEC MINUTE HOUR DAY MONTH YEAR DOW DST UTCOFF).
1379The optional TIME is the time value to convert. See 1379The optional TIME is the time value to convert. See
1380`format-time-string' for the various forms of a time value. 1380`format-time-string' for the various forms of a time value.
1381 1381
@@ -1385,29 +1385,33 @@ the TZ environment variable. It can also be a list (as from
1385`current-time-zone') or an integer (the UTC offset in seconds) applied 1385`current-time-zone') or an integer (the UTC offset in seconds) applied
1386without consideration for daylight saving time. 1386without consideration for daylight saving time.
1387 1387
1388The optional FORM specifies the form of the SEC member. If `integer',
1389SEC is an integer; if t, SEC uses the same resolution as TIME. An
1390omitted or nil FORM is currently treated like `integer', but this may
1391change in future Emacs versions.
1392
1388To access (or alter) the elements in the time value, the 1393To access (or alter) the elements in the time value, the
1389`decoded-time-second', `decoded-time-minute', `decoded-time-hour', 1394`decoded-time-second', `decoded-time-minute', `decoded-time-hour',
1390`decoded-time-day', `decoded-time-month', `decoded-time-year', 1395`decoded-time-day', `decoded-time-month', `decoded-time-year',
1391`decoded-time-weekday', `decoded-time-dst', `decoded-time-zone' and 1396`decoded-time-weekday', `decoded-time-dst' and `decoded-time-zone'
1392`decoded-time-subsec' accessors can be used. 1397accessors can be used.
1393 1398
1394The list has the following ten members: SEC is an integer between 0 1399The list has the following nine members: SEC is an integer or
1395and 60; SEC is 60 for a leap second, which only some operating systems 1400Lisp timestamp representing a nonnegative value less than 60
1396support. MINUTE is an integer between 0 and 59. HOUR is an integer 1401\(or less than 61 if the operating system supports leap seconds).
1402MINUTE is an integer between 0 and 59. HOUR is an integer
1397between 0 and 23. DAY is an integer between 1 and 31. MONTH is an 1403between 0 and 23. DAY is an integer between 1 and 31. MONTH is an
1398integer between 1 and 12. YEAR is an integer indicating the 1404integer between 1 and 12. YEAR is an integer indicating the
1399four-digit year. DOW is the day of week, an integer between 0 and 6, 1405four-digit year. DOW is the day of week, an integer between 0 and 6,
1400where 0 is Sunday. DST is t if daylight saving time is in effect, 1406where 0 is Sunday. DST is t if daylight saving time is in effect,
1401nil if it is not in effect, and -1 if daylight saving information is 1407nil if it is not in effect, and -1 if daylight saving information is
1402not available. UTCOFF is an integer indicating the UTC offset in 1408not available. UTCOFF is an integer indicating the UTC offset in
1403seconds, i.e., the number of seconds east of Greenwich. SUBSEC is 1409seconds, i.e., the number of seconds east of Greenwich. (Note that
1404is either 0 or (TICKS . HZ) where HZ is a positive integer clock 1410Common Lisp has different meanings for DOW and UTCOFF, and its
1405resolution and TICKS is a nonnegative integer less than HZ. (Note 1411SEC is always an integer between 0 and 59.)
1406that Common Lisp has different meanings for DOW and UTCOFF, and lacks
1407SUBSEC.)
1408 1412
1409usage: (decode-time &optional TIME ZONE) */) 1413usage: (decode-time &optional TIME ZONE FORM) */)
1410 (Lisp_Object specified_time, Lisp_Object zone) 1414 (Lisp_Object specified_time, Lisp_Object zone, Lisp_Object form)
1411{ 1415{
1412 struct lisp_time lt = lisp_time_struct (specified_time, 0); 1416 struct lisp_time lt = lisp_time_struct (specified_time, 0);
1413 struct timespec ts = lisp_to_timespec (lt); 1417 struct timespec ts = lisp_to_timespec (lt);
@@ -1439,8 +1443,35 @@ usage: (decode-time &optional TIME ZONE) */)
1439 year = make_integer_mpz (); 1443 year = make_integer_mpz ();
1440 } 1444 }
1441 1445
1446 Lisp_Object hz = lt.hz, sec;
1447 if (EQ (hz, make_fixnum (1)) || !EQ (form, Qt))
1448 sec = make_fixnum (local_tm.tm_sec);
1449 else
1450 {
1451 Lisp_Object ticks; /* hz * tm_sec + mod (lt.ticks, hz) */
1452 intmax_t n;
1453 if (FASTER_TIMEFNS && FIXNUMP (lt.ticks) && FIXNUMP (hz)
1454 && !INT_MULTIPLY_WRAPV (XFIXNUM (hz), local_tm.tm_sec, &n)
1455 && ! (INT_ADD_WRAPV
1456 (n, (XFIXNUM (lt.ticks) % XFIXNUM (hz)
1457 + (XFIXNUM (lt.ticks) % XFIXNUM (hz) < 0
1458 ? XFIXNUM (hz) : 0)),
1459 &n)))
1460 ticks = make_int (n);
1461 else
1462 {
1463 mpz_fdiv_r (mpz[0],
1464 *bignum_integer (&mpz[0], lt.ticks),
1465 *bignum_integer (&mpz[1], hz));
1466 mpz_addmul_ui (mpz[0], *bignum_integer (&mpz[1], hz),
1467 local_tm.tm_sec);
1468 ticks = make_integer_mpz ();
1469 }
1470 sec = Fcons (ticks, hz);
1471 }
1472
1442 return CALLN (Flist, 1473 return CALLN (Flist,
1443 make_fixnum (local_tm.tm_sec), 1474 sec,
1444 make_fixnum (local_tm.tm_min), 1475 make_fixnum (local_tm.tm_min),
1445 make_fixnum (local_tm.tm_hour), 1476 make_fixnum (local_tm.tm_hour),
1446 make_fixnum (local_tm.tm_mday), 1477 make_fixnum (local_tm.tm_mday),
@@ -1453,10 +1484,7 @@ usage: (decode-time &optional TIME ZONE) */)
1453 ? make_fixnum (tm_gmtoff (&local_tm)) 1484 ? make_fixnum (tm_gmtoff (&local_tm))
1454 : gmtime_r (&time_spec, &gmt_tm) 1485 : gmtime_r (&time_spec, &gmt_tm)
1455 ? make_fixnum (tm_diff (&local_tm, &gmt_tm)) 1486 ? make_fixnum (tm_diff (&local_tm, &gmt_tm))
1456 : Qnil), 1487 : Qnil));
1457 (EQ (lt.hz, make_fixnum (1))
1458 ? make_fixnum (0)
1459 : Fcons (integer_mod (lt.ticks, lt.hz), lt.hz)));
1460} 1488}
1461 1489
1462/* Return OBJ - OFFSET, checking that OBJ is a valid integer and that 1490/* Return OBJ - OFFSET, checking that OBJ is a valid integer and that
@@ -1487,7 +1515,7 @@ check_tm_member (Lisp_Object obj, int offset)
1487DEFUN ("encode-time", Fencode_time, Sencode_time, 1, MANY, 0, 1515DEFUN ("encode-time", Fencode_time, Sencode_time, 1, MANY, 0,
1488 doc: /* Convert TIME to a timestamp. 1516 doc: /* Convert TIME to a timestamp.
1489 1517
1490TIME is a list (SECOND MINUTE HOUR DAY MONTH YEAR IGNORED DST ZONE SUBSEC). 1518TIME is a list (SECOND MINUTE HOUR DAY MONTH YEAR IGNORED DST ZONE).
1491in the style of `decode-time', so that (encode-time (decode-time ...)) works. 1519in the style of `decode-time', so that (encode-time (decode-time ...)) works.
1492In this list, ZONE can be nil for Emacs local time, t for Universal 1520In this list, ZONE can be nil for Emacs local time, t for Universal
1493Time, `wall' for system wall clock time, or a string as in the TZ 1521Time, `wall' for system wall clock time, or a string as in the TZ
@@ -1496,23 +1524,16 @@ environment variable. It can also be a list (as from
1496without consideration for daylight saving time. If ZONE specifies a 1524without consideration for daylight saving time. If ZONE specifies a
1497time zone with daylight-saving transitions, DST is t for daylight 1525time zone with daylight-saving transitions, DST is t for daylight
1498saving time, nil for standard time, and -1 to cause the daylight 1526saving time, nil for standard time, and -1 to cause the daylight
1499saving flag to be guessed. SUBSEC is either 0 or a Lisp timestamp 1527saving flag to be guessed.
1500in (TICKS . HZ) form.
1501 1528
1502As an obsolescent calling convention, if this function is called with 1529As an obsolescent calling convention, if this function is called with
15036 through 10 arguments, the first 6 arguments are SECOND, MINUTE, 15306 or more arguments, the first 6 arguments are SECOND, MINUTE, HOUR,
1504HOUR, DAY, MONTH, and YEAR, and specify the components of a decoded 1531DAY, MONTH, and YEAR, and specify the components of a decoded time,
1505time. If there are 7 through 9 arguments the *last* argument 1532where DST assumed to be -1 and FORM is omitted. If there are more
1506specifies ZONE, and if there are 10 arguments the 9th specifies ZONE 1533than 6 arguments the *last* argument is used as ZONE and any other
1507and the 10th specifies SUBSEC; in either case any other extra 1534extra arguments are ignored, so that (apply #\\='encode-time
1508arguments are ignored, so that (apply #\\='encode-time (decode-time 1535(decode-time ...)) works. In this obsolescent convention, DST and
1509...)) works. In this obsolescent convention, DST, ZONE, and SUBSEC 1536ZONE default to -1 and nil respectively.
1510default to -1, nil and 0 respectively.
1511
1512Out-of-range values for SECOND, MINUTE, HOUR, DAY, or MONTH are allowed;
1513for example, a DAY of 0 means the day preceding the given month.
1514Year numbers less than 100 are treated just like other year numbers.
1515If you want them to stand for years in this century, you must do that yourself.
1516 1537
1517Years before 1970 are not guaranteed to work. On some systems, 1538Years before 1970 are not guaranteed to work. On some systems,
1518year values as low as 1901 do work. 1539year values as low as 1901 do work.
@@ -1521,27 +1542,27 @@ usage: (encode-time TIME &rest OBSOLESCENT-ARGUMENTS) */)
1521 (ptrdiff_t nargs, Lisp_Object *args) 1542 (ptrdiff_t nargs, Lisp_Object *args)
1522{ 1543{
1523 struct tm tm; 1544 struct tm tm;
1524 Lisp_Object zone = Qnil, subsec = make_fixnum (0); 1545 Lisp_Object zone = Qnil;
1525 Lisp_Object a = args[0]; 1546 Lisp_Object a = args[0];
1547 Lisp_Object secarg, minarg, hourarg, mdayarg, monarg, yeararg;
1526 tm.tm_isdst = -1; 1548 tm.tm_isdst = -1;
1527 1549
1528 if (nargs == 1) 1550 if (nargs == 1)
1529 { 1551 {
1530 Lisp_Object tail = a; 1552 Lisp_Object tail = a;
1531 for (int i = 0; i < 10; i++, tail = XCDR (tail)) 1553 for (int i = 0; i < 9; i++, tail = XCDR (tail))
1532 CHECK_CONS (tail); 1554 CHECK_CONS (tail);
1533 tm.tm_sec = check_tm_member (XCAR (a), 0); a = XCDR (a); 1555 secarg = XCAR (a); a = XCDR (a);
1534 tm.tm_min = check_tm_member (XCAR (a), 0); a = XCDR (a); 1556 minarg = XCAR (a); a = XCDR (a);
1535 tm.tm_hour = check_tm_member (XCAR (a), 0); a = XCDR (a); 1557 hourarg = XCAR (a); a = XCDR (a);
1536 tm.tm_mday = check_tm_member (XCAR (a), 0); a = XCDR (a); 1558 mdayarg = XCAR (a); a = XCDR (a);
1537 tm.tm_mon = check_tm_member (XCAR (a), 1); a = XCDR (a); 1559 monarg = XCAR (a); a = XCDR (a);
1538 tm.tm_year = check_tm_member (XCAR (a), TM_YEAR_BASE); a = XCDR (a); 1560 yeararg = XCAR (a); a = XCDR (a);
1539 a = XCDR (a); 1561 a = XCDR (a);
1540 Lisp_Object dstflag = XCAR (a); a = XCDR (a); 1562 Lisp_Object dstflag = XCAR (a); a = XCDR (a);
1541 zone = XCAR (a); a = XCDR (a); 1563 zone = XCAR (a);
1542 if (SYMBOLP (dstflag) && !FIXNUMP (zone) && !CONSP (zone)) 1564 if (SYMBOLP (dstflag) && !FIXNUMP (zone) && !CONSP (zone))
1543 tm.tm_isdst = !NILP (dstflag); 1565 tm.tm_isdst = !NILP (dstflag);
1544 subsec = XCAR (a);
1545 } 1566 }
1546 else if (nargs < 6) 1567 else if (nargs < 6)
1547 xsignal2 (Qwrong_number_of_arguments, Qencode_time, make_fixnum (nargs)); 1568 xsignal2 (Qwrong_number_of_arguments, Qencode_time, make_fixnum (nargs));
@@ -1549,18 +1570,37 @@ usage: (encode-time TIME &rest OBSOLESCENT-ARGUMENTS) */)
1549 { 1570 {
1550 if (6 < nargs) 1571 if (6 < nargs)
1551 zone = args[nargs - 1]; 1572 zone = args[nargs - 1];
1552 if (9 < nargs) 1573 secarg = a;
1553 { 1574 minarg = args[1];
1554 zone = args[8]; 1575 hourarg = args[2];
1555 subsec = args[9]; 1576 mdayarg = args[3];
1556 } 1577 monarg = args[4];
1557 tm.tm_sec = check_tm_member (a, 0); 1578 yeararg = args[5];
1558 tm.tm_min = check_tm_member (args[1], 0); 1579 }
1559 tm.tm_hour = check_tm_member (args[2], 0); 1580
1560 tm.tm_mday = check_tm_member (args[3], 0); 1581 struct lisp_time lt;
1561 tm.tm_mon = check_tm_member (args[4], 1); 1582 decode_lisp_time (secarg, 0, &lt, 0);
1562 tm.tm_year = check_tm_member (args[5], TM_YEAR_BASE); 1583 Lisp_Object hz = lt.hz, sec, subsecticks;
1584 if (FASTER_TIMEFNS && EQ (hz, make_fixnum (1)))
1585 {
1586 sec = lt.ticks;
1587 subsecticks = make_fixnum (0);
1588 }
1589 else
1590 {
1591 mpz_fdiv_qr (mpz[0], mpz[1],
1592 *bignum_integer (&mpz[0], lt.ticks),
1593 *bignum_integer (&mpz[1], hz));
1594 sec = make_integer_mpz ();
1595 mpz_swap (mpz[0], mpz[1]);
1596 subsecticks = make_integer_mpz ();
1563 } 1597 }
1598 tm.tm_sec = check_tm_member (sec, 0);
1599 tm.tm_min = check_tm_member (minarg, 0);
1600 tm.tm_hour = check_tm_member (hourarg, 0);
1601 tm.tm_mday = check_tm_member (mdayarg, 0);
1602 tm.tm_mon = check_tm_member (monarg, 1);
1603 tm.tm_year = check_tm_member (yeararg, TM_YEAR_BASE);
1564 1604
1565 timezone_t tz = tzlookup (zone, false); 1605 timezone_t tz = tzlookup (zone, false);
1566 tm.tm_wday = -1; 1606 tm.tm_wday = -1;
@@ -1571,25 +1611,17 @@ usage: (encode-time TIME &rest OBSOLESCENT-ARGUMENTS) */)
1571 if (tm.tm_wday < 0) 1611 if (tm.tm_wday < 0)
1572 time_error (mktime_errno); 1612 time_error (mktime_errno);
1573 1613
1574 if (CONSP (subsec)) 1614 if (EQ (hz, make_fixnum (1)))
1615 return (CURRENT_TIME_LIST
1616 ? list2 (hi_time (value), lo_time (value))
1617 : INT_TO_INTEGER (value));
1618 else
1575 { 1619 {
1576 Lisp_Object subsecticks = XCAR (subsec); 1620 struct lisp_time val1 = { INT_TO_INTEGER (value), make_fixnum (1) };
1577 if (INTEGERP (subsecticks)) 1621 Lisp_Object secticks = lisp_time_hz_ticks (val1, hz);
1578 { 1622 Lisp_Object ticks = lispint_arith (secticks, subsecticks, false);
1579 struct lisp_time val1 = { INT_TO_INTEGER (value), make_fixnum (1) }; 1623 return Fcons (ticks, hz);
1580 Lisp_Object
1581 hz = XCDR (subsec),
1582 secticks = lisp_time_hz_ticks (val1, hz),
1583 ticks = lispint_arith (secticks, subsecticks, false);
1584 return Fcons (ticks, hz);
1585 }
1586 } 1624 }
1587 else if (INTEGERP (subsec))
1588 return (CURRENT_TIME_LIST && EQ (subsec, make_fixnum (0))
1589 ? list2 (hi_time (value), lo_time (value))
1590 : lispint_arith (INT_TO_INTEGER (value), subsec, false));
1591
1592 xsignal2 (Qerror, build_string ("Invalid subsec"), subsec);
1593} 1625}
1594 1626
1595DEFUN ("time-convert", Ftime_convert, Stime_convert, 1, 2, 0, 1627DEFUN ("time-convert", Ftime_convert, Stime_convert, 1, 2, 0,
diff --git a/test/lisp/calendar/icalendar-tests.el b/test/lisp/calendar/icalendar-tests.el
index 060cd8c9091..baea4804045 100644
--- a/test/lisp/calendar/icalendar-tests.el
+++ b/test/lisp/calendar/icalendar-tests.el
@@ -477,18 +477,18 @@ END:VEVENT
477 477
478 ;; testcase: no time zone in input -> keep time as is 478 ;; testcase: no time zone in input -> keep time as is
479 ;; 1 Jan 2013 10:00 479 ;; 1 Jan 2013 10:00
480 (should (equal '(0 0 10 1 1 2013 2 nil 7200 0) 480 (should (equal '(0 0 10 1 1 2013 2 nil 7200)
481 (icalendar--decode-isodatetime "20130101T100000"))) 481 (icalendar--decode-isodatetime "20130101T100000")))
482 ;; 1 Aug 2013 10:00 (DST) 482 ;; 1 Aug 2013 10:00 (DST)
483 (should (equal '(0 0 10 1 8 2013 4 t 10800 0) 483 (should (equal '(0 0 10 1 8 2013 4 t 10800)
484 (icalendar--decode-isodatetime "20130801T100000"))) 484 (icalendar--decode-isodatetime "20130801T100000")))
485 485
486 ;; testcase: UTC time zone specifier in input -> convert to local time 486 ;; testcase: UTC time zone specifier in input -> convert to local time
487 ;; 31 Dec 2013 23:00 UTC -> 1 Jan 2013 01:00 EET 487 ;; 31 Dec 2013 23:00 UTC -> 1 Jan 2013 01:00 EET
488 (should (equal '(0 0 1 1 1 2014 3 nil 7200 0) 488 (should (equal '(0 0 1 1 1 2014 3 nil 7200)
489 (icalendar--decode-isodatetime "20131231T230000Z"))) 489 (icalendar--decode-isodatetime "20131231T230000Z")))
490 ;; 1 Aug 2013 10:00 UTC -> 1 Aug 2013 13:00 EEST 490 ;; 1 Aug 2013 10:00 UTC -> 1 Aug 2013 13:00 EEST
491 (should (equal '(0 0 13 1 8 2013 4 t 10800 0) 491 (should (equal '(0 0 13 1 8 2013 4 t 10800)
492 (icalendar--decode-isodatetime "20130801T100000Z"))) 492 (icalendar--decode-isodatetime "20130801T100000Z")))
493 493
494 ) 494 )
diff --git a/test/lisp/calendar/iso8601-tests.el b/test/lisp/calendar/iso8601-tests.el
index 3f1149c864d..35c319ed036 100644
--- a/test/lisp/calendar/iso8601-tests.el
+++ b/test/lisp/calendar/iso8601-tests.el
@@ -24,65 +24,65 @@
24 24
25(ert-deftest test-iso8601-date-years () 25(ert-deftest test-iso8601-date-years ()
26 (should (equal (iso8601-parse-date "1985") 26 (should (equal (iso8601-parse-date "1985")
27 '(nil nil nil nil nil 1985 nil nil nil nil))) 27 '(nil nil nil nil nil 1985 nil nil nil)))
28 (should (equal (iso8601-parse-date "-0003") 28 (should (equal (iso8601-parse-date "-0003")
29 '(nil nil nil nil nil -4 nil nil nil nil))) 29 '(nil nil nil nil nil -4 nil nil nil)))
30 (should (equal (iso8601-parse-date "+1985") 30 (should (equal (iso8601-parse-date "+1985")
31 '(nil nil nil nil nil 1985 nil nil nil nil)))) 31 '(nil nil nil nil nil 1985 nil nil nil))))
32 32
33(ert-deftest test-iso8601-date-dates () 33(ert-deftest test-iso8601-date-dates ()
34 (should (equal (iso8601-parse-date "1985-03-14") 34 (should (equal (iso8601-parse-date "1985-03-14")
35 '(nil nil nil 14 3 1985 nil nil nil nil))) 35 '(nil nil nil 14 3 1985 nil nil nil)))
36 (should (equal (iso8601-parse-date "19850314") 36 (should (equal (iso8601-parse-date "19850314")
37 '(nil nil nil 14 3 1985 nil nil nil nil))) 37 '(nil nil nil 14 3 1985 nil nil nil)))
38 (should (equal (iso8601-parse-date "1985-02") 38 (should (equal (iso8601-parse-date "1985-02")
39 '(nil nil nil nil 2 1985 nil nil nil nil)))) 39 '(nil nil nil nil 2 1985 nil nil nil))))
40 40
41(ert-deftest test-iso8601-date-obsolete () 41(ert-deftest test-iso8601-date-obsolete ()
42 (should (equal (iso8601-parse-date "--02-01") 42 (should (equal (iso8601-parse-date "--02-01")
43 '(nil nil nil 1 2 nil nil nil nil nil))) 43 '(nil nil nil 1 2 nil nil nil nil)))
44 (should (equal (iso8601-parse-date "--0201") 44 (should (equal (iso8601-parse-date "--0201")
45 '(nil nil nil 1 2 nil nil nil nil nil)))) 45 '(nil nil nil 1 2 nil nil nil nil))))
46 46
47(ert-deftest test-iso8601-date-weeks () 47(ert-deftest test-iso8601-date-weeks ()
48 (should (equal (iso8601-parse-date "2008W39-6") 48 (should (equal (iso8601-parse-date "2008W39-6")
49 '(nil nil nil 27 9 2008 nil nil nil nil))) 49 '(nil nil nil 27 9 2008 nil nil nil)))
50 (should (equal (iso8601-parse-date "2009W01-1") 50 (should (equal (iso8601-parse-date "2009W01-1")
51 '(nil nil nil 29 12 2008 nil nil nil nil))) 51 '(nil nil nil 29 12 2008 nil nil nil)))
52 (should (equal (iso8601-parse-date "2009W53-7") 52 (should (equal (iso8601-parse-date "2009W53-7")
53 '(nil nil nil 3 1 2010 nil nil nil nil)))) 53 '(nil nil nil 3 1 2010 nil nil nil))))
54 54
55(ert-deftest test-iso8601-date-ordinals () 55(ert-deftest test-iso8601-date-ordinals ()
56 (should (equal (iso8601-parse-date "1981-095") 56 (should (equal (iso8601-parse-date "1981-095")
57 '(nil nil nil 5 4 1981 nil nil nil nil)))) 57 '(nil nil nil 5 4 1981 nil nil nil))))
58 58
59(ert-deftest test-iso8601-time () 59(ert-deftest test-iso8601-time ()
60 (should (equal (iso8601-parse-time "13:47:30") 60 (should (equal (iso8601-parse-time "13:47:30")
61 '(30 47 13 nil nil nil nil nil nil 0))) 61 '(30 47 13 nil nil nil nil nil nil)))
62 (should (equal (iso8601-parse-time "134730") 62 (should (equal (iso8601-parse-time "134730")
63 '(30 47 13 nil nil nil nil nil nil 0))) 63 '(30 47 13 nil nil nil nil nil nil)))
64 (should (equal (iso8601-parse-time "1347") 64 (should (equal (iso8601-parse-time "1347")
65 '(0 47 13 nil nil nil nil nil nil 0)))) 65 '(0 47 13 nil nil nil nil nil nil))))
66 66
67(ert-deftest test-iso8601-combined () 67(ert-deftest test-iso8601-combined ()
68 (should (equal (iso8601-parse "2008-03-02T13:47:30") 68 (should (equal (iso8601-parse "2008-03-02T13:47:30")
69 '(30 47 13 2 3 2008 nil nil nil 0))) 69 '(30 47 13 2 3 2008 nil nil nil)))
70 (should (equal (iso8601-parse "2008-03-02T13:47:30Z") 70 (should (equal (iso8601-parse "2008-03-02T13:47:30Z")
71 '(30 47 13 2 3 2008 nil nil 0 0))) 71 '(30 47 13 2 3 2008 nil nil 0)))
72 (should (equal (iso8601-parse "2008-03-02T13:47:30+01:00") 72 (should (equal (iso8601-parse "2008-03-02T13:47:30+01:00")
73 '(30 47 13 2 3 2008 nil nil 3600 0))) 73 '(30 47 13 2 3 2008 nil nil 3600)))
74 (should (equal (iso8601-parse "2008-03-02T13:47:30-01") 74 (should (equal (iso8601-parse "2008-03-02T13:47:30-01")
75 '(30 47 13 2 3 2008 nil nil -3600 0)))) 75 '(30 47 13 2 3 2008 nil nil -3600))))
76 76
77(ert-deftest test-iso8601-duration () 77(ert-deftest test-iso8601-duration ()
78 (should (equal (iso8601-parse-duration "P3Y6M4DT12H30M5S") 78 (should (equal (iso8601-parse-duration "P3Y6M4DT12H30M5S")
79 '(5 30 12 4 6 3 nil nil nil 0))) 79 '(5 30 12 4 6 3 nil nil nil)))
80 (should (equal (iso8601-parse-duration "P1M") 80 (should (equal (iso8601-parse-duration "P1M")
81 '(0 0 0 0 1 0 nil nil nil 0))) 81 '(0 0 0 0 1 0 nil nil nil)))
82 (should (equal (iso8601-parse-duration "PT1M") 82 (should (equal (iso8601-parse-duration "PT1M")
83 '(0 1 0 0 0 0 nil nil nil 0))) 83 '(0 1 0 0 0 0 nil nil nil)))
84 (should (equal (iso8601-parse-duration "P0003-06-04T12:30:05") 84 (should (equal (iso8601-parse-duration "P0003-06-04T12:30:05")
85 '(5 30 12 4 6 3 nil nil nil 0)))) 85 '(5 30 12 4 6 3 nil nil nil))))
86 86
87(ert-deftest test-iso8601-invalid () 87(ert-deftest test-iso8601-invalid ()
88 (should-not (iso8601-valid-p " 2008-03-02T13:47:30-01")) 88 (should-not (iso8601-valid-p " 2008-03-02T13:47:30-01"))
@@ -94,149 +94,149 @@
94(ert-deftest test-iso8601-intervals () 94(ert-deftest test-iso8601-intervals ()
95 (should (equal 95 (should (equal
96 (iso8601-parse-interval "2007-03-01T13:00:00Z/2008-05-11T15:30:00Z") 96 (iso8601-parse-interval "2007-03-01T13:00:00Z/2008-05-11T15:30:00Z")
97 '((0 0 13 1 3 2007 nil nil 0 0) 97 '((0 0 13 1 3 2007 nil nil 0)
98 (0 30 15 11 5 2008 nil nil 0 0) 98 (0 30 15 11 5 2008 nil nil 0)
99 ;; Hm... can't really use decode-time for time differences... 99 ;; Hm... can't really use decode-time for time differences...
100 (0 30 2 14 3 1971 0 nil 0 0)))) 100 (0 30 2 14 3 1971 0 nil 0))))
101 (should (equal (iso8601-parse-interval "2007-03-01T13:00:00Z/P1Y2M10DT2H30M") 101 (should (equal (iso8601-parse-interval "2007-03-01T13:00:00Z/P1Y2M10DT2H30M")
102 '((0 0 13 1 3 2007 nil nil 0 0) 102 '((0 0 13 1 3 2007 nil nil 0)
103 (0 30 15 11 5 2008 nil nil 0 0) 103 (0 30 15 11 5 2008 nil nil 0)
104 (0 30 2 10 2 1 nil nil nil 0)))) 104 (0 30 2 10 2 1 nil nil nil))))
105 (should (equal (iso8601-parse-interval "P1Y2M10DT2H30M/2008-05-11T15:30:00Z") 105 (should (equal (iso8601-parse-interval "P1Y2M10DT2H30M/2008-05-11T15:30:00Z")
106 '((0 0 13 1 3 2007 nil nil 0 0) 106 '((0 0 13 1 3 2007 nil nil 0)
107 (0 30 15 11 5 2008 nil nil 0 0) 107 (0 30 15 11 5 2008 nil nil 0)
108 (0 30 2 10 2 1 nil nil nil 0))))) 108 (0 30 2 10 2 1 nil nil nil)))))
109 109
110(ert-deftest standard-test-dates () 110(ert-deftest standard-test-dates ()
111 (should (equal (iso8601-parse-date "19850412") 111 (should (equal (iso8601-parse-date "19850412")
112 '(nil nil nil 12 4 1985 nil nil nil nil))) 112 '(nil nil nil 12 4 1985 nil nil nil)))
113 (should (equal (iso8601-parse-date "1985-04-12") 113 (should (equal (iso8601-parse-date "1985-04-12")
114 '(nil nil nil 12 4 1985 nil nil nil nil))) 114 '(nil nil nil 12 4 1985 nil nil nil)))
115 115
116 (should (equal (iso8601-parse-date "1985102") 116 (should (equal (iso8601-parse-date "1985102")
117 '(nil nil nil 12 4 1985 nil nil nil nil))) 117 '(nil nil nil 12 4 1985 nil nil nil)))
118 (should (equal (iso8601-parse-date "1985-102") 118 (should (equal (iso8601-parse-date "1985-102")
119 '(nil nil nil 12 4 1985 nil nil nil nil))) 119 '(nil nil nil 12 4 1985 nil nil nil)))
120 120
121 (should (equal (iso8601-parse-date "1985W155") 121 (should (equal (iso8601-parse-date "1985W155")
122 '(nil nil nil 12 4 1985 nil nil nil nil))) 122 '(nil nil nil 12 4 1985 nil nil nil)))
123 (should (equal (iso8601-parse-date "1985-W15-5") 123 (should (equal (iso8601-parse-date "1985-W15-5")
124 '(nil nil nil 12 4 1985 nil nil nil nil))) 124 '(nil nil nil 12 4 1985 nil nil nil)))
125 125
126 (should (equal (iso8601-parse-date "1985W15") 126 (should (equal (iso8601-parse-date "1985W15")
127 '(nil nil nil 7 4 1985 nil nil nil nil))) 127 '(nil nil nil 7 4 1985 nil nil nil)))
128 (should (equal (iso8601-parse-date "1985-W15") 128 (should (equal (iso8601-parse-date "1985-W15")
129 '(nil nil nil 7 4 1985 nil nil nil nil))) 129 '(nil nil nil 7 4 1985 nil nil nil)))
130 130
131 (should (equal (iso8601-parse-date "1985-04") 131 (should (equal (iso8601-parse-date "1985-04")
132 '(nil nil nil nil 4 1985 nil nil nil nil))) 132 '(nil nil nil nil 4 1985 nil nil nil)))
133 133
134 (should (equal (iso8601-parse-date "1985") 134 (should (equal (iso8601-parse-date "1985")
135 '(nil nil nil nil nil 1985 nil nil nil nil))) 135 '(nil nil nil nil nil 1985 nil nil nil)))
136 136
137 (should (equal (iso8601-parse-date "+1985-04-12") 137 (should (equal (iso8601-parse-date "+1985-04-12")
138 '(nil nil nil 12 4 1985 nil nil nil nil))) 138 '(nil nil nil 12 4 1985 nil nil nil)))
139 (should (equal (iso8601-parse-date "+19850412") 139 (should (equal (iso8601-parse-date "+19850412")
140 '(nil nil nil 12 4 1985 nil nil nil nil)))) 140 '(nil nil nil 12 4 1985 nil nil nil))))
141 141
142(ert-deftest standard-test-time-of-day-local-time () 142(ert-deftest standard-test-time-of-day-local-time ()
143 (should (equal (iso8601-parse-time "152746") 143 (should (equal (iso8601-parse-time "152746")
144 '(46 27 15 nil nil nil nil nil nil 0))) 144 '(46 27 15 nil nil nil nil nil nil)))
145 (should (equal (iso8601-parse-time "15:27:46") 145 (should (equal (iso8601-parse-time "15:27:46")
146 '(46 27 15 nil nil nil nil nil nil 0))) 146 '(46 27 15 nil nil nil nil nil nil)))
147 147
148 (should (equal (iso8601-parse-time "1528") 148 (should (equal (iso8601-parse-time "1528")
149 '(0 28 15 nil nil nil nil nil nil 0))) 149 '(0 28 15 nil nil nil nil nil nil)))
150 (should (equal (iso8601-parse-time "15:28") 150 (should (equal (iso8601-parse-time "15:28")
151 '(0 28 15 nil nil nil nil nil nil 0))) 151 '(0 28 15 nil nil nil nil nil nil)))
152 152
153 (should (equal (iso8601-parse-time "15") 153 (should (equal (iso8601-parse-time "15")
154 '(0 0 15 nil nil nil nil nil nil 0)))) 154 '(0 0 15 nil nil nil nil nil nil))))
155 155
156(ert-deftest standard-test-time-of-day-fractions () 156(ert-deftest standard-test-time-of-day-fractions ()
157 ;; decoded-time doesn't support sub-second times. 157 ;; decoded-time doesn't support sub-second times.
158 ;; (should (equal (iso8601-parse-time "152735,5") 158 ;; (should (equal (iso8601-parse-time "152735,5")
159 ;; '(46 27 15 nil nil nil nil nil nil (5 . 10)))) 159 ;; '(46 27 15 nil nil nil nil nil nil)))
160 ;; (should (equal (iso8601-parse-time "15:27:35,5") 160 ;; (should (equal (iso8601-parse-time "15:27:35,5")
161 ;; '(46 27 15 nil nil nil nil nil nil (5 . 10)))) 161 ;; '(46 27 15 nil nil nil nil nil nil)))
162 ) 162 )
163 163
164(ert-deftest standard-test-time-of-day-beginning-of-day () 164(ert-deftest standard-test-time-of-day-beginning-of-day ()
165 (should (equal (iso8601-parse-time "000000") 165 (should (equal (iso8601-parse-time "000000")
166 '(0 0 0 nil nil nil nil nil nil 0))) 166 '(0 0 0 nil nil nil nil nil nil)))
167 (should (equal (iso8601-parse-time "00:00:00") 167 (should (equal (iso8601-parse-time "00:00:00")
168 '(0 0 0 nil nil nil nil nil nil 0))) 168 '(0 0 0 nil nil nil nil nil nil)))
169 169
170 (should (equal (iso8601-parse-time "0000") 170 (should (equal (iso8601-parse-time "0000")
171 '(0 0 0 nil nil nil nil nil nil 0))) 171 '(0 0 0 nil nil nil nil nil nil)))
172 (should (equal (iso8601-parse-time "00:00") 172 (should (equal (iso8601-parse-time "00:00")
173 '(0 0 0 nil nil nil nil nil nil 0)))) 173 '(0 0 0 nil nil nil nil nil nil))))
174 174
175(ert-deftest standard-test-time-of-day-utc () 175(ert-deftest standard-test-time-of-day-utc ()
176 (should (equal (iso8601-parse-time "232030Z") 176 (should (equal (iso8601-parse-time "232030Z")
177 '(30 20 23 nil nil nil nil nil 0 0))) 177 '(30 20 23 nil nil nil nil nil 0)))
178 (should (equal (iso8601-parse-time "23:20:30Z") 178 (should (equal (iso8601-parse-time "23:20:30Z")
179 '(30 20 23 nil nil nil nil nil 0 0))) 179 '(30 20 23 nil nil nil nil nil 0)))
180 180
181 (should (equal (iso8601-parse-time "2320Z") 181 (should (equal (iso8601-parse-time "2320Z")
182 '(0 20 23 nil nil nil nil nil 0 0))) 182 '(0 20 23 nil nil nil nil nil 0)))
183 (should (equal (iso8601-parse-time "23:20Z") 183 (should (equal (iso8601-parse-time "23:20Z")
184 '(0 20 23 nil nil nil nil nil 0 0))) 184 '(0 20 23 nil nil nil nil nil 0)))
185 185
186 (should (equal (iso8601-parse-time "23Z") 186 (should (equal (iso8601-parse-time "23Z")
187 '(0 0 23 nil nil nil nil nil 0 0)))) 187 '(0 0 23 nil nil nil nil nil 0))))
188 188
189 189
190(ert-deftest standard-test-time-of-day-zone () 190(ert-deftest standard-test-time-of-day-zone ()
191 (should (equal (iso8601-parse-time "152746+0100") 191 (should (equal (iso8601-parse-time "152746+0100")
192 '(46 27 15 nil nil nil nil nil 3600 0))) 192 '(46 27 15 nil nil nil nil nil 3600)))
193 (should (equal (iso8601-parse-time "15:27:46+0100") 193 (should (equal (iso8601-parse-time "15:27:46+0100")
194 '(46 27 15 nil nil nil nil nil 3600 0))) 194 '(46 27 15 nil nil nil nil nil 3600)))
195 195
196 (should (equal (iso8601-parse-time "152746+01") 196 (should (equal (iso8601-parse-time "152746+01")
197 '(46 27 15 nil nil nil nil nil 3600 0))) 197 '(46 27 15 nil nil nil nil nil 3600)))
198 (should (equal (iso8601-parse-time "15:27:46+01") 198 (should (equal (iso8601-parse-time "15:27:46+01")
199 '(46 27 15 nil nil nil nil nil 3600 0))) 199 '(46 27 15 nil nil nil nil nil 3600)))
200 200
201 (should (equal (iso8601-parse-time "152746-0500") 201 (should (equal (iso8601-parse-time "152746-0500")
202 '(46 27 15 nil nil nil nil nil -18000 0))) 202 '(46 27 15 nil nil nil nil nil -18000)))
203 (should (equal (iso8601-parse-time "15:27:46-0500") 203 (should (equal (iso8601-parse-time "15:27:46-0500")
204 '(46 27 15 nil nil nil nil nil -18000 0))) 204 '(46 27 15 nil nil nil nil nil -18000)))
205 205
206 (should (equal (iso8601-parse-time "152746-05") 206 (should (equal (iso8601-parse-time "152746-05")
207 '(46 27 15 nil nil nil nil nil -18000 0))) 207 '(46 27 15 nil nil nil nil nil -18000)))
208 (should (equal (iso8601-parse-time "15:27:46-05") 208 (should (equal (iso8601-parse-time "15:27:46-05")
209 '(46 27 15 nil nil nil nil nil -18000 0)))) 209 '(46 27 15 nil nil nil nil nil -18000))))
210 210
211(ert-deftest standard-test-date-and-time-of-day () 211(ert-deftest standard-test-date-and-time-of-day ()
212 (should (equal (iso8601-parse "19850412T101530") 212 (should (equal (iso8601-parse "19850412T101530")
213 '(30 15 10 12 4 1985 nil nil nil 0))) 213 '(30 15 10 12 4 1985 nil nil nil)))
214 (should (equal (iso8601-parse "1985-04-12T10:15:30") 214 (should (equal (iso8601-parse "1985-04-12T10:15:30")
215 '(30 15 10 12 4 1985 nil nil nil 0))) 215 '(30 15 10 12 4 1985 nil nil nil)))
216 216
217 (should (equal (iso8601-parse "1985102T235030Z") 217 (should (equal (iso8601-parse "1985102T235030Z")
218 '(30 50 23 12 4 1985 nil nil 0 0))) 218 '(30 50 23 12 4 1985 nil nil 0)))
219 (should (equal (iso8601-parse "1985-102T23:50:30Z") 219 (should (equal (iso8601-parse "1985-102T23:50:30Z")
220 '(30 50 23 12 4 1985 nil nil 0 0))) 220 '(30 50 23 12 4 1985 nil nil 0)))
221 221
222 (should (equal (iso8601-parse "1985W155T235030") 222 (should (equal (iso8601-parse "1985W155T235030")
223 '(30 50 23 12 4 1985 nil nil nil 0))) 223 '(30 50 23 12 4 1985 nil nil nil)))
224 (should (equal (iso8601-parse "1985-W155T23:50:30") 224 (should (equal (iso8601-parse "1985-W155T23:50:30")
225 '(30 50 23 12 4 1985 nil nil nil 0)))) 225 '(30 50 23 12 4 1985 nil nil nil))))
226 226
227(ert-deftest standard-test-interval () 227(ert-deftest standard-test-interval ()
228 ;; A time interval starting at 20 minutes and 50 seconds past 23 228 ;; A time interval starting at 20 minutes and 50 seconds past 23
229 ;; hours on 12 April 1985 and ending at 30 minutes past 10 hours on 229 ;; hours on 12 April 1985 and ending at 30 minutes past 10 hours on
230 ;; 25 June 1985. 230 ;; 25 June 1985.
231 (should (equal (iso8601-parse-interval "19850412T232050Z/19850625T103000Z") 231 (should (equal (iso8601-parse-interval "19850412T232050Z/19850625T103000Z")
232 '((50 20 23 12 4 1985 nil nil 0 0) 232 '((50 20 23 12 4 1985 nil nil 0)
233 (0 30 10 25 6 1985 nil nil 0 0) 233 (0 30 10 25 6 1985 nil nil 0)
234 (10 9 11 15 3 1970 0 nil 0 0)))) 234 (10 9 11 15 3 1970 0 nil 0))))
235 (should (equal (iso8601-parse-interval 235 (should (equal (iso8601-parse-interval
236 "1985-04-12T23:20:50Z/1985-06-25T10:30:00Z") 236 "1985-04-12T23:20:50Z/1985-06-25T10:30:00Z")
237 '((50 20 23 12 4 1985 nil nil 0 0) 237 '((50 20 23 12 4 1985 nil nil 0)
238 (0 30 10 25 6 1985 nil nil 0 0) 238 (0 30 10 25 6 1985 nil nil 0)
239 (10 9 11 15 3 1970 0 nil 0 0)))) 239 (10 9 11 15 3 1970 0 nil 0))))
240 240
241 ;; A time interval starting at 12 April 1985 and ending on 25 June 241 ;; A time interval starting at 12 April 1985 and ending on 25 June
242 ;; 1985. 242 ;; 1985.
@@ -251,41 +251,41 @@
251 ;; A time interval of 2 years, 10 months, 15 days, 10 hours, 20 251 ;; A time interval of 2 years, 10 months, 15 days, 10 hours, 20
252 ;; minutes and 30 seconds. 252 ;; minutes and 30 seconds.
253 (should (equal (iso8601-parse-duration "P2Y10M15DT10H20M30S") 253 (should (equal (iso8601-parse-duration "P2Y10M15DT10H20M30S")
254 '(30 20 10 15 10 2 nil nil nil 0))) 254 '(30 20 10 15 10 2 nil nil nil)))
255 255
256 (should (equal (iso8601-parse-duration "P00021015T102030") 256 (should (equal (iso8601-parse-duration "P00021015T102030")
257 '(30 20 10 15 10 2 nil nil nil 0))) 257 '(30 20 10 15 10 2 nil nil nil)))
258 (should (equal (iso8601-parse-duration "P0002-10-15T10:20:30") 258 (should (equal (iso8601-parse-duration "P0002-10-15T10:20:30")
259 '(30 20 10 15 10 2 nil nil nil 0))) 259 '(30 20 10 15 10 2 nil nil nil)))
260 260
261 ;; A time interval of 1 year and 6 months. 261 ;; A time interval of 1 year and 6 months.
262 (should (equal (iso8601-parse-duration "P1Y6M") 262 (should (equal (iso8601-parse-duration "P1Y6M")
263 '(0 0 0 0 6 1 nil nil nil 0))) 263 '(0 0 0 0 6 1 nil nil nil)))
264 (should (equal (iso8601-parse-duration "P0001-06") 264 (should (equal (iso8601-parse-duration "P0001-06")
265 '(nil nil nil nil 6 1 nil nil nil nil))) 265 '(nil nil nil nil 6 1 nil nil nil)))
266 266
267 ;; A time interval of seventy-two hours. 267 ;; A time interval of seventy-two hours.
268 (should (equal (iso8601-parse-duration "PT72H") 268 (should (equal (iso8601-parse-duration "PT72H")
269 '(0 0 72 0 0 0 nil nil nil 0))) 269 '(0 0 72 0 0 0 nil nil nil)))
270 270
271 ;; Defined by start and duration 271 ;; Defined by start and duration
272 ;; A time interval of 1 year, 2 months, 15 days and 12 hours, 272 ;; A time interval of 1 year, 2 months, 15 days and 12 hours,
273 ;; beginning on 12 April 1985 at 20 minutes past 23 hours. 273 ;; beginning on 12 April 1985 at 20 minutes past 23 hours.
274 (should (equal (iso8601-parse-interval "19850412T232000/P1Y2M15DT12H") 274 (should (equal (iso8601-parse-interval "19850412T232000/P1Y2M15DT12H")
275 '((0 20 23 12 4 1985 nil nil nil 0) 275 '((0 20 23 12 4 1985 nil nil nil)
276 (0 20 11 28 6 1986 nil nil nil 0) 276 (0 20 11 28 6 1986 nil nil nil)
277 (0 0 12 15 2 1 nil nil nil 0)))) 277 (0 0 12 15 2 1 nil nil nil))))
278 (should (equal (iso8601-parse-interval "1985-04-12T23:20:00/P1Y2M15DT12H") 278 (should (equal (iso8601-parse-interval "1985-04-12T23:20:00/P1Y2M15DT12H")
279 '((0 20 23 12 4 1985 nil nil nil 0) 279 '((0 20 23 12 4 1985 nil nil nil)
280 (0 20 11 28 6 1986 nil nil nil 0) 280 (0 20 11 28 6 1986 nil nil nil)
281 (0 0 12 15 2 1 nil nil nil 0)))) 281 (0 0 12 15 2 1 nil nil nil))))
282 282
283 ;; Defined by duration and end 283 ;; Defined by duration and end
284 ;; A time interval of 1 year, 2 months, 15 days and 12 hours, ending 284 ;; A time interval of 1 year, 2 months, 15 days and 12 hours, ending
285 ;; on 12 April 1985 at 20 minutes past 23 hour. 285 ;; on 12 April 1985 at 20 minutes past 23 hour.
286 (should (equal (iso8601-parse-interval "P1Y2M15DT12H/19850412T232000") 286 (should (equal (iso8601-parse-interval "P1Y2M15DT12H/19850412T232000")
287 '((0 20 11 28 1 1984 nil nil nil 0) 287 '((0 20 11 28 1 1984 nil nil nil)
288 (0 20 23 12 4 1985 nil nil nil 0) 288 (0 20 23 12 4 1985 nil nil nil)
289 (0 0 12 15 2 1 nil nil nil 0))))) 289 (0 0 12 15 2 1 nil nil nil)))))
290 290
291;;; iso8601-tests.el ends here 291;;; iso8601-tests.el ends here
diff --git a/test/lisp/calendar/parse-time-tests.el b/test/lisp/calendar/parse-time-tests.el
index 61a3838a52b..7435620b71f 100644
--- a/test/lisp/calendar/parse-time-tests.el
+++ b/test/lisp/calendar/parse-time-tests.el
@@ -28,23 +28,23 @@
28 28
29(ert-deftest parse-time-tests () 29(ert-deftest parse-time-tests ()
30 (should (equal (parse-time-string "Mon, 22 Feb 2016 19:35:42 +0100") 30 (should (equal (parse-time-string "Mon, 22 Feb 2016 19:35:42 +0100")
31 '(42 35 19 22 2 2016 1 -1 3600 0))) 31 '(42 35 19 22 2 2016 1 -1 3600)))
32 (should (equal (parse-time-string "22 Feb 2016 19:35:42 +0100") 32 (should (equal (parse-time-string "22 Feb 2016 19:35:42 +0100")
33 '(42 35 19 22 2 2016 nil -1 3600 0))) 33 '(42 35 19 22 2 2016 nil -1 3600)))
34 (should (equal (parse-time-string "22 Feb 2016 +0100") 34 (should (equal (parse-time-string "22 Feb 2016 +0100")
35 '(nil nil nil 22 2 2016 nil -1 3600 nil))) 35 '(nil nil nil 22 2 2016 nil -1 3600)))
36 (should (equal (parse-time-string "Mon, 22 Feb 16 19:35:42 +0100") 36 (should (equal (parse-time-string "Mon, 22 Feb 16 19:35:42 +0100")
37 '(42 35 19 22 2 2016 1 -1 3600 0))) 37 '(42 35 19 22 2 2016 1 -1 3600)))
38 (should (equal (parse-time-string "Mon, 22 February 2016 19:35:42 +0100") 38 (should (equal (parse-time-string "Mon, 22 February 2016 19:35:42 +0100")
39 '(42 35 19 22 2 2016 1 -1 3600 0))) 39 '(42 35 19 22 2 2016 1 -1 3600)))
40 (should (equal (parse-time-string "Mon, 22 feb 2016 19:35:42 +0100") 40 (should (equal (parse-time-string "Mon, 22 feb 2016 19:35:42 +0100")
41 '(42 35 19 22 2 2016 1 -1 3600 0))) 41 '(42 35 19 22 2 2016 1 -1 3600)))
42 (should (equal (parse-time-string "Monday, 22 february 2016 19:35:42 +0100") 42 (should (equal (parse-time-string "Monday, 22 february 2016 19:35:42 +0100")
43 '(42 35 19 22 2 2016 1 -1 3600 0))) 43 '(42 35 19 22 2 2016 1 -1 3600)))
44 (should (equal (parse-time-string "Monday, 22 february 2016 19:35:42 PST") 44 (should (equal (parse-time-string "Monday, 22 february 2016 19:35:42 PST")
45 '(42 35 19 22 2 2016 1 nil -28800 0))) 45 '(42 35 19 22 2 2016 1 nil -28800)))
46 (should (equal (parse-time-string "Friday, 21 Sep 2018 13:47:58 PDT") 46 (should (equal (parse-time-string "Friday, 21 Sep 2018 13:47:58 PDT")
47 '(58 47 13 21 9 2018 5 t -25200 0))) 47 '(58 47 13 21 9 2018 5 t -25200)))
48 (should (equal (format-time-string 48 (should (equal (format-time-string
49 "%Y-%m-%d %H:%M:%S" 49 "%Y-%m-%d %H:%M:%S"
50 (parse-iso8601-time-string "1998-09-12T12:21:54-0200") t) 50 (parse-iso8601-time-string "1998-09-12T12:21:54-0200") t)
diff --git a/test/src/timefns-tests.el b/test/src/timefns-tests.el
index 362e7655a91..13ab7d83c3e 100644
--- a/test/src/timefns-tests.el
+++ b/test/src/timefns-tests.el
@@ -40,25 +40,31 @@
40 (7879679999900 . 100000) 40 (7879679999900 . 100000)
41 (78796799999999999999 . 1000000000000))) 41 (78796799999999999999 . 1000000000000)))
42 ;; UTC. 42 ;; UTC.
43 (let ((subsec (time-subtract (time-convert look t) 43 (let ((sec (time-add 59 (time-subtract (time-convert look t)
44 (time-convert look 'integer)))) 44 (time-convert look 'integer)))))
45 (should (string-equal 45 (should (string-equal
46 (format-time-string "%Y-%m-%d %H:%M:%S.%3N %z" look t) 46 (format-time-string "%Y-%m-%d %H:%M:%S.%3N %z" look t)
47 "1972-06-30 23:59:59.999 +0000")) 47 "1972-06-30 23:59:59.999 +0000"))
48 (should (equal (decode-time look t) 48 (should (equal (decode-time look t 'integer)
49 (list 59 59 23 30 6 1972 5 nil 0 subsec))) 49 '(59 59 23 30 6 1972 5 nil 0)))
50 (should (equal (decode-time look t t)
51 (list sec 59 23 30 6 1972 5 nil 0)))
50 ;; "UTC0". 52 ;; "UTC0".
51 (should (string-equal 53 (should (string-equal
52 (format-time-string format look "UTC0") 54 (format-time-string format look "UTC0")
53 "1972-06-30 23:59:59.999 +0000 (UTC)")) 55 "1972-06-30 23:59:59.999 +0000 (UTC)"))
54 (should (equal (decode-time look "UTC0") 56 (should (equal (decode-time look "UTC0" 'integer)
55 (list 59 59 23 30 6 1972 5 nil 0 subsec))) 57 '(59 59 23 30 6 1972 5 nil 0)))
58 (should (equal (decode-time look "UTC0" t)
59 (list sec 59 23 30 6 1972 5 nil 0)))
56 ;; Negative UTC offset, as a Lisp list. 60 ;; Negative UTC offset, as a Lisp list.
57 (should (string-equal 61 (should (string-equal
58 (format-time-string format look '(-28800 "PST")) 62 (format-time-string format look '(-28800 "PST"))
59 "1972-06-30 15:59:59.999 -0800 (PST)")) 63 "1972-06-30 15:59:59.999 -0800 (PST)"))
60 (should (equal (decode-time look '(-28800 "PST")) 64 (should (equal (decode-time look '(-28800 "PST") 'integer)
61 (list 59 59 15 30 6 1972 5 nil -28800 subsec))) 65 '(59 59 15 30 6 1972 5 nil -28800)))
66 (should (equal (decode-time look '(-28800 "PST") t)
67 (list sec 59 15 30 6 1972 5 nil -28800)))
62 ;; Negative UTC offset, as a Lisp integer. 68 ;; Negative UTC offset, as a Lisp integer.
63 (should (string-equal 69 (should (string-equal
64 (format-time-string format look -28800) 70 (format-time-string format look -28800)
@@ -67,14 +73,18 @@
67 (if (eq system-type 'windows-nt) 73 (if (eq system-type 'windows-nt)
68 "1972-06-30 15:59:59.999 -0800 (ZZZ)" 74 "1972-06-30 15:59:59.999 -0800 (ZZZ)"
69 "1972-06-30 15:59:59.999 -0800 (-08)"))) 75 "1972-06-30 15:59:59.999 -0800 (-08)")))
70 (should (equal (decode-time look -28800) 76 (should (equal (decode-time look -28800 'integer)
71 (list 59 59 15 30 6 1972 5 nil -28800 subsec))) 77 '(59 59 15 30 6 1972 5 nil -28800)))
78 (should (equal (decode-time look -28800 t)
79 (list sec 59 15 30 6 1972 5 nil -28800)))
72 ;; Positive UTC offset that is not an hour multiple, as a string. 80 ;; Positive UTC offset that is not an hour multiple, as a string.
73 (should (string-equal 81 (should (string-equal
74 (format-time-string format look "IST-5:30") 82 (format-time-string format look "IST-5:30")
75 "1972-07-01 05:29:59.999 +0530 (IST)")) 83 "1972-07-01 05:29:59.999 +0530 (IST)"))
76 (should (equal (decode-time look "IST-5:30") 84 (should (equal (decode-time look "IST-5:30" 'integer)
77 (list 59 29 5 1 7 1972 6 nil 19800 subsec))))))) 85 '(59 29 5 1 7 1972 6 nil 19800)))
86 (should (equal (decode-time look "IST-5:30" t)
87 (list sec 29 5 1 7 1972 6 nil 19800)))))))
78 88
79(ert-deftest decode-then-encode-time () 89(ert-deftest decode-then-encode-time ()
80 (let ((time-values (list 0 -2 1 0.0 -0.0 -2.0 1.0 90 (let ((time-values (list 0 -2 1 0.0 -0.0 -2.0 1.0
@@ -87,11 +97,13 @@
87 (cons (1+ most-positive-fixnum) 1000000000000) 97 (cons (1+ most-positive-fixnum) 1000000000000)
88 (cons 1000000000000 (1+ most-positive-fixnum))))) 98 (cons 1000000000000 (1+ most-positive-fixnum)))))
89 (dolist (a time-values) 99 (dolist (a time-values)
90 (let* ((d (ignore-errors (decode-time a t))) 100 (let* ((d (ignore-errors (decode-time a t t)))
101 (d-integer (ignore-errors (decode-time a t 'integer)))
91 (e (if d (encode-time d))) 102 (e (if d (encode-time d)))
92 (diff (float-time (time-subtract a e)))) 103 (e-integer (if d-integer (encode-time d-integer))))
93 (should (or (not d) 104 (should (or (not d) (time-equal-p a e)))
94 (and (<= 0 diff) (< diff 1)))))))) 105 (should (or (not d-integer) (time-equal-p (time-convert a 'integer)
106 e-integer)))))))
95 107
96;;; This should not dump core. 108;;; This should not dump core.
97(ert-deftest format-time-string-with-outlandish-zone () 109(ert-deftest format-time-string-with-outlandish-zone ()
@@ -151,7 +163,7 @@
151(ert-deftest encode-time-dst-numeric-zone () 163(ert-deftest encode-time-dst-numeric-zone ()
152 "Check for Bug#35502." 164 "Check for Bug#35502."
153 (should (time-equal-p 165 (should (time-equal-p
154 (encode-time '(29 31 17 30 4 2019 2 t 7200 0)) 166 (encode-time '(29 31 17 30 4 2019 2 t 7200))
155 '(23752 27217)))) 167 '(23752 27217))))
156 168
157(ert-deftest float-time-precision () 169(ert-deftest float-time-precision ()