Merge branch 'master' of git.savannah.gnu.org:/srv/git/emacs

This commit is contained in:
Eli Zaretskii 2019-08-17 12:25:32 +03:00
commit abd3fdf7b8
15 changed files with 344 additions and 311 deletions

View file

@ -1478,23 +1478,23 @@ Although @code{(time-convert nil nil)} is equivalent to
@end example
@end defun
@defun decode-time &optional time zone
@defun decode-time &optional time zone form
This function converts a time value into calendrical information. If
you don't specify @var{time}, it decodes the current time, and similarly
@var{zone} defaults to the current time zone rule. @xref{Time Zone Rules}.
The return value is a list of ten elements, as follows:
The @var{form} argument controls the form of the returned
@var{seconds} element, as described below.
The return value is a list of nine elements, as follows:
@example
(@var{seconds} @var{minutes} @var{hour} @var{day} @var{month} @var{year}
@var{dow} @var{dst} @var{utcoff} @var{subsec})
(@var{seconds} @var{minutes} @var{hour} @var{day} @var{month} @var{year} @var{dow} @var{dst} @var{utcoff})
@end example
Here is what the elements mean:
@table @var
@item seconds
The number of seconds past the minute, as an integer between 0 and 59.
On some operating systems, this is 60 for leap seconds.
The number of seconds past the minute, with form described below.
@item minutes
The number of minutes past the hour, as an integer between 0 and 59.
@item hour
@ -1514,22 +1514,33 @@ in effect, and @minus{}1 if this information is not available.
@item utcoff
An integer indicating the Universal Time offset in seconds, i.e., the number of
seconds east of Greenwich.
@item subsec
The number of subseconds past the second, as either 0 or a Lisp
timestamp @code{(@var{ticks} . @var{hz})} representing a nonnegative
fraction less than 1.
@end table
The @var{seconds} element is a Lisp timestamp that is nonnegative and
less than 61; it is less than 60 except during positive leap seconds
(assuming the operating system supports leap seconds). If the
optional @var{form} argument is @code{t}, @var{seconds} uses the same
precision as @var{time}; if @var{form} is @code{integer},
@var{seconds} is truncated to an integer. For example, if @var{time}
is the timestamp @code{(1566009571321 . 1000)}, which represents
2019-08-17 02:39:31.321 UTC on typical systems that lack leap seconds,
then @code{(decode-time @var{time} t t)} returns @code{((31321 . 1000)
39 2 17 8 2019 6 nil 0)}, whereas @code{(decode-time @var{time} t
'integer)} returns @code{(31 39 2 17 8 2019 6 nil 0)}. If @var{form}
is omitted or @code{nil}, it currently defaults to @code{integer} but
this default may change in future Emacs releases, so callers requiring
a particular form should specify @var{form}.
@strong{Common Lisp Note:} Common Lisp has different meanings for
@var{dow} and @var{utcoff}, and lacks @var{subsec}.
@var{dow} and @var{utcoff}, and its @var{second} is an integer between
0 and 59 inclusive.
To access (or alter) the elements in the time value, the
@code{decoded-time-second}, @code{decoded-time-minute},
@code{decoded-time-hour}, @code{decoded-time-day},
@code{decoded-time-month}, @code{decoded-time-year},
@code{decoded-time-weekday}, @code{decoded-time-dst},
@code{decoded-time-zone} and @code{decoded-time-subsec}
accessors can be used.
@code{decoded-time-weekday}, @code{decoded-time-dst} and
@code{decoded-time-zone} accessors can be used.
For instance, to increase the year in a decoded time, you could say:
@ -1551,7 +1562,7 @@ For instance, if you want ``same time next month'', you
could say:
@lisp
(let ((time (decode-time))
(let ((time (decode-time nil nil t))
(delta (make-decoded-time :month 2)))
(encode-time (decoded-time-add time delta)))
@end lisp
@ -1585,22 +1596,21 @@ It can act as the inverse of @code{decode-time}.
Ordinarily the first argument is a list
@code{(@var{second} @var{minute} @var{hour} @var{day} @var{month}
@var{year} @var{ignored} @var{dst} @var{zone} @var{subsec})} that specifies a
@var{year} @var{ignored} @var{dst} @var{zone})} that specifies a
decoded time in the style of @code{decode-time}, so that
@code{(encode-time (decode-time ...))} works. For the meanings of
these list members, see the table under @code{decode-time}.
As an obsolescent calling convention, this function can be given six
through ten arguments. The first six arguments @var{second},
or more arguments. The first six arguments @var{second},
@var{minute}, @var{hour}, @var{day}, @var{month}, and @var{year}
specify most of the components of a decoded time. If there are seven
through nine arguments the @emph{last} argument is used as @var{zone},
and if there are ten arguments the ninth specifies @var{zone} and the
tenth specifies @var{subsec}; in either case any other extra arguments
are ignored, so that @code{(apply #'encode-time (decode-time ...))}
works. In this obsolescent convention, @var{zone} defaults to the
current time zone rule (@pxref{Time Zone Rules}), @var{subsec}
defaults to 0, and @var{dst} is treated as if it was @minus{}1.
specify most of the components of a decoded time. If there are more
than six arguments the @emph{last} argument is used as @var{zone} and
any other extra arguments are ignored, so that @code{(apply
#'encode-time (decode-time ...))} works. In this obsolescent
convention, @var{zone} defaults to the current time zone rule
(@pxref{Time Zone Rules}), and @var{dst} is treated as if it was
@minus{}1.
Year numbers less than 100 are not treated specially. If you want them
to stand for years above 1900, or years above 2000, you must alter them
@ -1615,9 +1625,8 @@ the latter to the former as follows:
@end example
You can perform simple date arithmetic by using out-of-range values for
@var{seconds}, @var{minutes}, @var{hour}, @var{day}, @var{month}, and
@var{subsec}; for example, day 0 means the day preceding the given
month.
@var{seconds}, @var{minutes}, @var{hour}, @var{day}, and @var{month};
for example, day 0 means the day preceding the given month.
The operating system puts limits on the range of possible time values;
if the limits are exceeded while encoding the time, an error results.

View file

@ -1535,7 +1535,7 @@ Here's a bunch of time/date/second/day examples:
@example
(parse-time-string "Sat Sep 12 12:21:54 1998 +0200")
@result{} (54 21 12 12 9 1998 6 -1 7200 0)
@result{} (54 21 12 12 9 1998 6 -1 7200)
(time-convert
(date-to-time "Sat Sep 12 12:21:54 1998 +0200")

View file

@ -2116,10 +2116,20 @@ probing the innards of a timestamp directly, or creating a timestamp
by hand.
+++
*** Decoded (calendrical) timestamps now have a new subsecond member.
This affects functions like decode-time and parse-time-string that
generate these timestamps, and functions like encode-time that accept
them.
*** Decoded (calendrical) timestamps now have subsecond resolution.
This affects decode-time, which generates these timestamps, as well as
functions like encode-time that accept them. The subsecond info is
present as a (TICKS . HZ) value in the seconds element of a decoded
timestamp, and decode-time has a new optional FORM argument specifying
the form of the seconds member. For example, if X is the timestamp
(1566009571321878186 . 1000000000), which represents 2019-08-17
02:39:31.321878186 UTC, (decode-time X t t) returns ((31321878186
. 1000000000) 39 2 17 8 2019 6 nil 0) instead of the traditional (31
39 2 17 8 2019 6 nil 0) returned by plain (decode-time X t). Although
the default FORM is currently 'integer', which truncates the seconds
to an integer and is the traditional behavior, this default may change
in future Emacs versions, so callers requiring an integer should
specify FORM explicitly.
+++
*** 'encode-time' supports a new API '(encode-time TIME)'.
@ -2152,8 +2162,8 @@ with POSIX.1-2017.
*** To access (or alter) the elements a decoded time value, the
'decoded-time-second', 'decoded-time-minute', 'decoded-time-hour',
'decoded-time-day', 'decoded-time-month', 'decoded-time-year',
'decoded-time-weekday', 'decoded-time-dst', 'decoded-time-zone',
and 'decoded-time-subsec' accessors can be used.
'decoded-time-weekday', 'decoded-time-dst' and 'decoded-time-zone'
accessors can be used.
*** The new functions 'date-days-in-month' (which will say how many
days there are in a month in a specific year), 'date-ordinal-to-time'

View file

@ -644,7 +644,7 @@ FIXME: multiple comma-separated values should be allowed!"
;; create the decoded date-time
;; FIXME!?!
(let ((decoded-time (list second minute hour day month year
nil -1 zone 0)))
nil -1 zone)))
(condition-case nil
(decode-time (encode-time decoded-time))
(error

View file

@ -129,8 +129,7 @@ well as variants like \"2008W32\" (week number) and
(let ((time (iso8601-parse-time time-string)))
(setf (decoded-time-hour date) (decoded-time-hour time))
(setf (decoded-time-minute date) (decoded-time-minute time))
(setf (decoded-time-second date) (decoded-time-second time))
(setf (decoded-time-subsec date) (decoded-time-subsec time))))
(setf (decoded-time-second date) (decoded-time-second time))))
;; The time zone is optional.
(when zone-string
(setf (decoded-time-zone date)
@ -237,8 +236,6 @@ well as variants like \"2008W32\" (week number) and
(iso8601--decoded-time :hour hour
:minute (or minute 0)
:second (or second 0)
;; FIXME: Support subsec.
:subsec 0
:zone (and zone
(* 60 (iso8601-parse-zone
zone)))))))))
@ -277,9 +274,7 @@ Return the number of minutes."
:day (or (match-string 3 string) 0)
:hour (or (match-string 5 string) 0)
:minute (or (match-string 6 string) 0)
:second (or (match-string 7 string) 0)
;; FIXME: Support subsec.
:subsec 0))
:second (or (match-string 7 string) 0)))
;; PnW: Weeks.
((iso8601--match iso8601--duration-week-match string)
(let ((weeks (string-to-number (match-string 1 string))))
@ -341,7 +336,7 @@ Return the number of minutes."
(cl-defun iso8601--decoded-time (&key second minute hour
day month year
dst zone subsec)
dst zone)
(list (iso8601--value second)
(iso8601--value minute)
(iso8601--value hour)
@ -350,8 +345,7 @@ Return the number of minutes."
(iso8601--value year)
nil
dst
zone
subsec))
zone))
(defun iso8601--encode-time (time)
"Like `encode-time', but fill in nil values in TIME."

View file

@ -148,7 +148,7 @@ letters, digits, plus or minus signs or colons."
;;;###autoload
(defun parse-time-string (string)
"Parse the time in STRING into (SEC MIN HOUR DAY MON YEAR DOW DST TZ SUBSEC).
"Parse the time in STRING into (SEC MIN HOUR DAY MON YEAR DOW DST TZ).
STRING should be something resembling an RFC 822 (or later) date-time, e.g.,
\"Fri, 25 Mar 2016 16:24:56 +0100\", but this function is
somewhat liberal in what format it accepts, and will attempt to
@ -156,7 +156,7 @@ return a \"likely\" value even for somewhat malformed strings.
The values returned are identical to those of `decode-time', but
any unknown values other than DST are returned as nil, and an
unknown DST value is returned as -1."
(let ((time (list nil nil nil nil nil nil nil -1 nil nil))
(let ((time (list nil nil nil nil nil nil nil -1 nil))
(temp (parse-time-tokenize (downcase string))))
(while temp
(let ((parse-time-elt (pop temp))
@ -193,10 +193,6 @@ unknown DST value is returned as -1."
(funcall this)))
parse-time-val)))
(setf (nth (pop slots) time) new-val))))))))
;; FIXME: Currently parse-time-string does not parse subseconds.
;; So if seconds were found, set subseconds to zero.
(when (nth 0 time)
(setf (nth 9 time) 0))
time))
(defun parse-iso8601-time-string (date-string)

View file

@ -420,26 +420,13 @@ changes in daylight saving time are not taken into account."
;; Do the time part, which is pretty simple (except for leap
;; seconds, I guess).
(setq seconds (+ (* (or (decoded-time-hour delta) 0) 3600)
(* (or (decoded-time-minute delta) 0) 60)
(or (decoded-time-second delta) 0)))
(when (decoded-time-subsec delta)
(let* ((subsec (time-convert (time-add (decoded-time-subsec time)
(decoded-time-subsec delta))
t))
(s (time-convert subsec 'integer)))
(setq seconds (+ seconds s))
(setf (decoded-time-subsec time) (time-subtract subsec s))))
;; Time zone adjustments are basically the same as time adjustments.
(setq seconds (+ seconds (or (decoded-time-zone delta) 0)))
(cond
((> seconds 0)
(decoded-time--alter-second time seconds t))
((< seconds 0)
(decoded-time--alter-second time (abs seconds) nil)))
(setq seconds (time-add (+ (* (or (decoded-time-hour delta) 0) 3600)
(* (or (decoded-time-minute delta) 0) 60)
(or (decoded-time-zone delta) 0))
(or (decoded-time-second delta) 0)))
(decoded-time--alter-second time seconds)
time))
(defun decoded-time--alter-month (time increase)
@ -472,38 +459,31 @@ changes in daylight saving time are not taken into account."
(date-days-in-month (decoded-time-year time)
(decoded-time-month time))))))
(defun decoded-time--alter-second (time seconds increase)
"Increase or decrease the time in TIME by SECONDS."
(let ((old (+ (* (or (decoded-time-hour time) 0) 3600)
(* (or (decoded-time-minute time) 0) 60)
(or (decoded-time-second time) 0))))
(if increase
(progn
(setq old (+ old seconds))
(setf (decoded-time-second time) (% old 60)
(decoded-time-minute time) (% (/ old 60) 60)
(decoded-time-hour time) (% (/ old 3600) 24))
;; Hm... DST...
(let ((days (/ old (* 60 60 24))))
(while (> days 0)
(decoded-time--alter-day time t)
(cl-decf days))))
(setq old (abs (- old seconds)))
(setf (decoded-time-second time) (% old 60)
(decoded-time-minute time) (% (/ old 60) 60)
(decoded-time-hour time) (% (/ old 3600) 24))
;; Hm... DST...
(let ((days (/ old (* 60 60 24))))
(while (> days 0)
(decoded-time--alter-day time nil)
(cl-decf days))))))
(defun decoded-time--alter-second (time seconds)
"Increase the time in TIME by SECONDS."
(let* ((secsperday 86400)
(old (time-add (+ (* 3600 (or (decoded-time-hour time) 0))
(* 60 (or (decoded-time-minute time) 0)))
(or (decoded-time-second time) 0)))
(new (time-add old seconds)))
;; Hm... DST...
(while (time-less-p new 0)
(decoded-time--alter-day time nil)
(setq new (time-add new secsperday)))
(while (not (time-less-p new secsperday))
(decoded-time--alter-day time t)
(setq new (time-subtract new secsperday)))
(let ((sec (time-convert new 'integer)))
(setf (decoded-time-second time) (time-add (% sec 60)
(time-subtract new sec))
(decoded-time-minute time) (% (/ sec 60) 60)
(decoded-time-hour time) (/ sec 3600)))))
(cl-defun make-decoded-time (&key second minute hour
day month year
dst zone subsec)
dst zone)
"Return a `decoded-time' structure with only the keywords given filled out."
(list second minute hour day month year nil dst zone subsec))
(list second minute hour day month year nil dst zone))
(defun decoded-time-set-defaults (time &optional default-zone)
"Set any nil values in `decoded-time' TIME to default values.
@ -533,9 +513,6 @@ TIME is modified and returned."
(when (and (not (decoded-time-zone time))
default-zone)
(setf (decoded-time-zone time) 0))
(unless (decoded-time-subsec time)
(setf (decoded-time-subsec time) 0))
time)
(provide 'time-date)

View file

@ -561,8 +561,8 @@ gMonthDay, gDay or gMonth.
Return a list in a format (SEC MINUTE HOUR DAY MONTH YEAR
SEC-FRACTION DATATYPE ZONE). This format is meant to be similar
to that returned by `decode-time' (and compatible with
`encode-time'). The differences are the SUBSEC (fractional
seconds) field is omitted, the DOW (day-of-week) field
`encode-time'). The differences are the SEC (seconds)
field is always an integer, the DOW (day-of-week) field
is replaced with SEC-FRACTION, a float representing the
fractional seconds, and the DST (daylight savings time) field is
replaced with DATATYPE, a symbol representing the XSD primitive

View file

@ -17775,12 +17775,14 @@ NODEFAULT, hour and minute fields will be nil if not given."
(string-to-number (match-string 4 s))
(string-to-number (match-string 3 s))
(string-to-number (match-string 2 s))
nil nil nil 0))
nil nil nil))
((string-match "^<[^>]+>$" s)
;; FIXME: `decode-time' needs to be called with ZONE as its
;; second argument. However, this requires at least Emacs
;; 25.1. We can do it when we switch to this version as our
;; minimal requirement.
;; FIXME: decode-time needs to be called with t as its
;; third argument, but this requires at least Emacs 27.
(decode-time (org-matcher-time s)))
(t (error "Not a standard Org time string: %s" s))))

View file

@ -9082,8 +9082,9 @@ to capitalize ARG words."
(:copier nil)
(:type list))
(second nil :documentation "\
This is an integer between 0 and 60 (inclusive). (60 is a leap
second, which only some operating systems support.)")
This is an integer or a Lisp timestamp (TICKS . HZ) representing a nonnegative
number of seconds less than 61. (If not less than 60, it is a leap second,
which only some operating systems support.)")
(minute nil :documentation "This is an integer between 0 and 59 (inclusive).")
(hour nil :documentation "This is an integer between 0 and 23 (inclusive).")
(day nil :documentation "This is an integer between 1 and 31 (inclusive).")
@ -9099,9 +9100,6 @@ available.")
(zone nil :documentation "\
This is an integer indicating the UTC offset in seconds, i.e.,
the number of seconds east of Greenwich.")
(subsec nil :documentation "\
This is 0, or is an integer pair (TICKS . HZ) indicating TICKS/HZ seconds,
where HZ is positive and TICKS is nonnegative and less than HZ.")
)

View file

@ -1090,11 +1090,14 @@ time_arith (Lisp_Object a, Lisp_Object b, bool subtract)
}
/* Return an integer if the timestamp resolution is 1,
otherwise the (TICKS . HZ) form if either argument is that way,
otherwise the (HI LO US PS) form for backward compatibility. */
otherwise the (TICKS . HZ) form if !CURRENT_TIME_LIST or if
either input form supports timestamps that cannot be expressed
exactly in (HI LO US PS) form, otherwise the (HI LO US PS) form
for backward compatibility. */
return (EQ (hz, make_fixnum (1))
? ticks
: timeform_sub_ps_p (aform) || timeform_sub_ps_p (bform)
: (!CURRENT_TIME_LIST
|| timeform_sub_ps_p (aform) || timeform_sub_ps_p (bform))
? Fcons (ticks, hz)
: ticks_hz_list4 (ticks, hz));
}
@ -1374,8 +1377,8 @@ usage: (format-time-string FORMAT-STRING &optional TIME ZONE) */)
t, zone, &tm);
}
DEFUN ("decode-time", Fdecode_time, Sdecode_time, 0, 2, 0,
doc: /* Decode a time value as (SEC MINUTE HOUR DAY MONTH YEAR DOW DST UTCOFF SUBSEC).
DEFUN ("decode-time", Fdecode_time, Sdecode_time, 0, 3, 0,
doc: /* Decode a time value as (SEC MINUTE HOUR DAY MONTH YEAR DOW DST UTCOFF).
The optional TIME is the time value to convert. See
`format-time-string' for the various forms of a time value.
@ -1385,29 +1388,33 @@ the TZ environment variable. It can also be a list (as from
`current-time-zone') or an integer (the UTC offset in seconds) applied
without consideration for daylight saving time.
The optional FORM specifies the form of the SEC member. If `integer',
SEC is an integer; if t, SEC uses the same resolution as TIME. An
omitted or nil FORM is currently treated like `integer', but this may
change in future Emacs versions.
To access (or alter) the elements in the time value, the
`decoded-time-second', `decoded-time-minute', `decoded-time-hour',
`decoded-time-day', `decoded-time-month', `decoded-time-year',
`decoded-time-weekday', `decoded-time-dst', `decoded-time-zone' and
`decoded-time-subsec' accessors can be used.
`decoded-time-weekday', `decoded-time-dst' and `decoded-time-zone'
accessors can be used.
The list has the following ten members: SEC is an integer between 0
and 60; SEC is 60 for a leap second, which only some operating systems
support. MINUTE is an integer between 0 and 59. HOUR is an integer
The list has the following nine members: SEC is an integer or
Lisp timestamp representing a nonnegative value less than 60
\(or less than 61 if the operating system supports leap seconds).
MINUTE is an integer between 0 and 59. HOUR is an integer
between 0 and 23. DAY is an integer between 1 and 31. MONTH is an
integer between 1 and 12. YEAR is an integer indicating the
four-digit year. DOW is the day of week, an integer between 0 and 6,
where 0 is Sunday. DST is t if daylight saving time is in effect,
nil if it is not in effect, and -1 if daylight saving information is
not available. UTCOFF is an integer indicating the UTC offset in
seconds, i.e., the number of seconds east of Greenwich. SUBSEC is
is either 0 or (TICKS . HZ) where HZ is a positive integer clock
resolution and TICKS is a nonnegative integer less than HZ. (Note
that Common Lisp has different meanings for DOW and UTCOFF, and lacks
SUBSEC.)
seconds, i.e., the number of seconds east of Greenwich. (Note that
Common Lisp has different meanings for DOW and UTCOFF, and its
SEC is always an integer between 0 and 59.)
usage: (decode-time &optional TIME ZONE) */)
(Lisp_Object specified_time, Lisp_Object zone)
usage: (decode-time &optional TIME ZONE FORM) */)
(Lisp_Object specified_time, Lisp_Object zone, Lisp_Object form)
{
struct lisp_time lt = lisp_time_struct (specified_time, 0);
struct timespec ts = lisp_to_timespec (lt);
@ -1439,8 +1446,35 @@ usage: (decode-time &optional TIME ZONE) */)
year = make_integer_mpz ();
}
Lisp_Object hz = lt.hz, sec;
if (EQ (hz, make_fixnum (1)) || !EQ (form, Qt))
sec = make_fixnum (local_tm.tm_sec);
else
{
Lisp_Object ticks; /* hz * tm_sec + mod (lt.ticks, hz) */
intmax_t n;
if (FASTER_TIMEFNS && FIXNUMP (lt.ticks) && FIXNUMP (hz)
&& !INT_MULTIPLY_WRAPV (XFIXNUM (hz), local_tm.tm_sec, &n)
&& ! (INT_ADD_WRAPV
(n, (XFIXNUM (lt.ticks) % XFIXNUM (hz)
+ (XFIXNUM (lt.ticks) % XFIXNUM (hz) < 0
? XFIXNUM (hz) : 0)),
&n)))
ticks = make_int (n);
else
{
mpz_fdiv_r (mpz[0],
*bignum_integer (&mpz[0], lt.ticks),
*bignum_integer (&mpz[1], hz));
mpz_addmul_ui (mpz[0], *bignum_integer (&mpz[1], hz),
local_tm.tm_sec);
ticks = make_integer_mpz ();
}
sec = Fcons (ticks, hz);
}
return CALLN (Flist,
make_fixnum (local_tm.tm_sec),
sec,
make_fixnum (local_tm.tm_min),
make_fixnum (local_tm.tm_hour),
make_fixnum (local_tm.tm_mday),
@ -1453,10 +1487,7 @@ usage: (decode-time &optional TIME ZONE) */)
? make_fixnum (tm_gmtoff (&local_tm))
: gmtime_r (&time_spec, &gmt_tm)
? make_fixnum (tm_diff (&local_tm, &gmt_tm))
: Qnil),
(EQ (lt.hz, make_fixnum (1))
? make_fixnum (0)
: Fcons (integer_mod (lt.ticks, lt.hz), lt.hz)));
: Qnil));
}
/* Return OBJ - OFFSET, checking that OBJ is a valid integer and that
@ -1487,7 +1518,7 @@ check_tm_member (Lisp_Object obj, int offset)
DEFUN ("encode-time", Fencode_time, Sencode_time, 1, MANY, 0,
doc: /* Convert TIME to a timestamp.
TIME is a list (SECOND MINUTE HOUR DAY MONTH YEAR IGNORED DST ZONE SUBSEC).
TIME is a list (SECOND MINUTE HOUR DAY MONTH YEAR IGNORED DST ZONE).
in the style of `decode-time', so that (encode-time (decode-time ...)) works.
In this list, ZONE can be nil for Emacs local time, t for Universal
Time, `wall' for system wall clock time, or a string as in the TZ
@ -1496,23 +1527,16 @@ environment variable. It can also be a list (as from
without consideration for daylight saving time. If ZONE specifies a
time zone with daylight-saving transitions, DST is t for daylight
saving time, nil for standard time, and -1 to cause the daylight
saving flag to be guessed. SUBSEC is either 0 or a Lisp timestamp
in (TICKS . HZ) form.
saving flag to be guessed.
As an obsolescent calling convention, if this function is called with
6 through 10 arguments, the first 6 arguments are SECOND, MINUTE,
HOUR, DAY, MONTH, and YEAR, and specify the components of a decoded
time. If there are 7 through 9 arguments the *last* argument
specifies ZONE, and if there are 10 arguments the 9th specifies ZONE
and the 10th specifies SUBSEC; in either case any other extra
arguments are ignored, so that (apply #\\='encode-time (decode-time
...)) works. In this obsolescent convention, DST, ZONE, and SUBSEC
default to -1, nil and 0 respectively.
Out-of-range values for SECOND, MINUTE, HOUR, DAY, or MONTH are allowed;
for example, a DAY of 0 means the day preceding the given month.
Year numbers less than 100 are treated just like other year numbers.
If you want them to stand for years in this century, you must do that yourself.
6 or more arguments, the first 6 arguments are SECOND, MINUTE, HOUR,
DAY, MONTH, and YEAR, and specify the components of a decoded time,
where DST assumed to be -1 and FORM is omitted. If there are more
than 6 arguments the *last* argument is used as ZONE and any other
extra arguments are ignored, so that (apply #\\='encode-time
(decode-time ...)) works. In this obsolescent convention, DST and
ZONE default to -1 and nil respectively.
Years before 1970 are not guaranteed to work. On some systems,
year values as low as 1901 do work.
@ -1521,27 +1545,27 @@ usage: (encode-time TIME &rest OBSOLESCENT-ARGUMENTS) */)
(ptrdiff_t nargs, Lisp_Object *args)
{
struct tm tm;
Lisp_Object zone = Qnil, subsec = make_fixnum (0);
Lisp_Object zone = Qnil;
Lisp_Object a = args[0];
Lisp_Object secarg, minarg, hourarg, mdayarg, monarg, yeararg;
tm.tm_isdst = -1;
if (nargs == 1)
{
Lisp_Object tail = a;
for (int i = 0; i < 10; i++, tail = XCDR (tail))
for (int i = 0; i < 9; i++, tail = XCDR (tail))
CHECK_CONS (tail);
tm.tm_sec = check_tm_member (XCAR (a), 0); a = XCDR (a);
tm.tm_min = check_tm_member (XCAR (a), 0); a = XCDR (a);
tm.tm_hour = check_tm_member (XCAR (a), 0); a = XCDR (a);
tm.tm_mday = check_tm_member (XCAR (a), 0); a = XCDR (a);
tm.tm_mon = check_tm_member (XCAR (a), 1); a = XCDR (a);
tm.tm_year = check_tm_member (XCAR (a), TM_YEAR_BASE); a = XCDR (a);
secarg = XCAR (a); a = XCDR (a);
minarg = XCAR (a); a = XCDR (a);
hourarg = XCAR (a); a = XCDR (a);
mdayarg = XCAR (a); a = XCDR (a);
monarg = XCAR (a); a = XCDR (a);
yeararg = XCAR (a); a = XCDR (a);
a = XCDR (a);
Lisp_Object dstflag = XCAR (a); a = XCDR (a);
zone = XCAR (a); a = XCDR (a);
zone = XCAR (a);
if (SYMBOLP (dstflag) && !FIXNUMP (zone) && !CONSP (zone))
tm.tm_isdst = !NILP (dstflag);
subsec = XCAR (a);
}
else if (nargs < 6)
xsignal2 (Qwrong_number_of_arguments, Qencode_time, make_fixnum (nargs));
@ -1549,19 +1573,38 @@ usage: (encode-time TIME &rest OBSOLESCENT-ARGUMENTS) */)
{
if (6 < nargs)
zone = args[nargs - 1];
if (9 < nargs)
{
zone = args[8];
subsec = args[9];
}
tm.tm_sec = check_tm_member (a, 0);
tm.tm_min = check_tm_member (args[1], 0);
tm.tm_hour = check_tm_member (args[2], 0);
tm.tm_mday = check_tm_member (args[3], 0);
tm.tm_mon = check_tm_member (args[4], 1);
tm.tm_year = check_tm_member (args[5], TM_YEAR_BASE);
secarg = a;
minarg = args[1];
hourarg = args[2];
mdayarg = args[3];
monarg = args[4];
yeararg = args[5];
}
struct lisp_time lt;
decode_lisp_time (secarg, 0, &lt, 0);
Lisp_Object hz = lt.hz, sec, subsecticks;
if (FASTER_TIMEFNS && EQ (hz, make_fixnum (1)))
{
sec = lt.ticks;
subsecticks = make_fixnum (0);
}
else
{
mpz_fdiv_qr (mpz[0], mpz[1],
*bignum_integer (&mpz[0], lt.ticks),
*bignum_integer (&mpz[1], hz));
sec = make_integer_mpz ();
mpz_swap (mpz[0], mpz[1]);
subsecticks = make_integer_mpz ();
}
tm.tm_sec = check_tm_member (sec, 0);
tm.tm_min = check_tm_member (minarg, 0);
tm.tm_hour = check_tm_member (hourarg, 0);
tm.tm_mday = check_tm_member (mdayarg, 0);
tm.tm_mon = check_tm_member (monarg, 1);
tm.tm_year = check_tm_member (yeararg, TM_YEAR_BASE);
timezone_t tz = tzlookup (zone, false);
tm.tm_wday = -1;
time_t value = mktime_z (tz, &tm);
@ -1571,25 +1614,17 @@ usage: (encode-time TIME &rest OBSOLESCENT-ARGUMENTS) */)
if (tm.tm_wday < 0)
time_error (mktime_errno);
if (CONSP (subsec))
{
Lisp_Object subsecticks = XCAR (subsec);
if (INTEGERP (subsecticks))
{
struct lisp_time val1 = { INT_TO_INTEGER (value), make_fixnum (1) };
Lisp_Object
hz = XCDR (subsec),
secticks = lisp_time_hz_ticks (val1, hz),
ticks = lispint_arith (secticks, subsecticks, false);
return Fcons (ticks, hz);
}
}
else if (INTEGERP (subsec))
return (CURRENT_TIME_LIST && EQ (subsec, make_fixnum (0))
if (EQ (hz, make_fixnum (1)))
return (CURRENT_TIME_LIST
? list2 (hi_time (value), lo_time (value))
: lispint_arith (INT_TO_INTEGER (value), subsec, false));
xsignal2 (Qerror, build_string ("Invalid subsec"), subsec);
: INT_TO_INTEGER (value));
else
{
struct lisp_time val1 = { INT_TO_INTEGER (value), make_fixnum (1) };
Lisp_Object secticks = lisp_time_hz_ticks (val1, hz);
Lisp_Object ticks = lispint_arith (secticks, subsecticks, false);
return Fcons (ticks, hz);
}
}
DEFUN ("time-convert", Ftime_convert, Stime_convert, 1, 2, 0,

View file

@ -477,18 +477,18 @@ END:VEVENT
;; testcase: no time zone in input -> keep time as is
;; 1 Jan 2013 10:00
(should (equal '(0 0 10 1 1 2013 2 nil 7200 0)
(should (equal '(0 0 10 1 1 2013 2 nil 7200)
(icalendar--decode-isodatetime "20130101T100000")))
;; 1 Aug 2013 10:00 (DST)
(should (equal '(0 0 10 1 8 2013 4 t 10800 0)
(should (equal '(0 0 10 1 8 2013 4 t 10800)
(icalendar--decode-isodatetime "20130801T100000")))
;; testcase: UTC time zone specifier in input -> convert to local time
;; 31 Dec 2013 23:00 UTC -> 1 Jan 2013 01:00 EET
(should (equal '(0 0 1 1 1 2014 3 nil 7200 0)
(should (equal '(0 0 1 1 1 2014 3 nil 7200)
(icalendar--decode-isodatetime "20131231T230000Z")))
;; 1 Aug 2013 10:00 UTC -> 1 Aug 2013 13:00 EEST
(should (equal '(0 0 13 1 8 2013 4 t 10800 0)
(should (equal '(0 0 13 1 8 2013 4 t 10800)
(icalendar--decode-isodatetime "20130801T100000Z")))
)

View file

@ -24,65 +24,65 @@
(ert-deftest test-iso8601-date-years ()
(should (equal (iso8601-parse-date "1985")
'(nil nil nil nil nil 1985 nil nil nil nil)))
'(nil nil nil nil nil 1985 nil nil nil)))
(should (equal (iso8601-parse-date "-0003")
'(nil nil nil nil nil -4 nil nil nil nil)))
'(nil nil nil nil nil -4 nil nil nil)))
(should (equal (iso8601-parse-date "+1985")
'(nil nil nil nil nil 1985 nil nil nil nil))))
'(nil nil nil nil nil 1985 nil nil nil))))
(ert-deftest test-iso8601-date-dates ()
(should (equal (iso8601-parse-date "1985-03-14")
'(nil nil nil 14 3 1985 nil nil nil nil)))
'(nil nil nil 14 3 1985 nil nil nil)))
(should (equal (iso8601-parse-date "19850314")
'(nil nil nil 14 3 1985 nil nil nil nil)))
'(nil nil nil 14 3 1985 nil nil nil)))
(should (equal (iso8601-parse-date "1985-02")
'(nil nil nil nil 2 1985 nil nil nil nil))))
'(nil nil nil nil 2 1985 nil nil nil))))
(ert-deftest test-iso8601-date-obsolete ()
(should (equal (iso8601-parse-date "--02-01")
'(nil nil nil 1 2 nil nil nil nil nil)))
'(nil nil nil 1 2 nil nil nil nil)))
(should (equal (iso8601-parse-date "--0201")
'(nil nil nil 1 2 nil nil nil nil nil))))
'(nil nil nil 1 2 nil nil nil nil))))
(ert-deftest test-iso8601-date-weeks ()
(should (equal (iso8601-parse-date "2008W39-6")
'(nil nil nil 27 9 2008 nil nil nil nil)))
'(nil nil nil 27 9 2008 nil nil nil)))
(should (equal (iso8601-parse-date "2009W01-1")
'(nil nil nil 29 12 2008 nil nil nil nil)))
'(nil nil nil 29 12 2008 nil nil nil)))
(should (equal (iso8601-parse-date "2009W53-7")
'(nil nil nil 3 1 2010 nil nil nil nil))))
'(nil nil nil 3 1 2010 nil nil nil))))
(ert-deftest test-iso8601-date-ordinals ()
(should (equal (iso8601-parse-date "1981-095")
'(nil nil nil 5 4 1981 nil nil nil nil))))
'(nil nil nil 5 4 1981 nil nil nil))))
(ert-deftest test-iso8601-time ()
(should (equal (iso8601-parse-time "13:47:30")
'(30 47 13 nil nil nil nil nil nil 0)))
'(30 47 13 nil nil nil nil nil nil)))
(should (equal (iso8601-parse-time "134730")
'(30 47 13 nil nil nil nil nil nil 0)))
'(30 47 13 nil nil nil nil nil nil)))
(should (equal (iso8601-parse-time "1347")
'(0 47 13 nil nil nil nil nil nil 0))))
'(0 47 13 nil nil nil nil nil nil))))
(ert-deftest test-iso8601-combined ()
(should (equal (iso8601-parse "2008-03-02T13:47:30")
'(30 47 13 2 3 2008 nil nil nil 0)))
'(30 47 13 2 3 2008 nil nil nil)))
(should (equal (iso8601-parse "2008-03-02T13:47:30Z")
'(30 47 13 2 3 2008 nil nil 0 0)))
'(30 47 13 2 3 2008 nil nil 0)))
(should (equal (iso8601-parse "2008-03-02T13:47:30+01:00")
'(30 47 13 2 3 2008 nil nil 3600 0)))
'(30 47 13 2 3 2008 nil nil 3600)))
(should (equal (iso8601-parse "2008-03-02T13:47:30-01")
'(30 47 13 2 3 2008 nil nil -3600 0))))
'(30 47 13 2 3 2008 nil nil -3600))))
(ert-deftest test-iso8601-duration ()
(should (equal (iso8601-parse-duration "P3Y6M4DT12H30M5S")
'(5 30 12 4 6 3 nil nil nil 0)))
'(5 30 12 4 6 3 nil nil nil)))
(should (equal (iso8601-parse-duration "P1M")
'(0 0 0 0 1 0 nil nil nil 0)))
'(0 0 0 0 1 0 nil nil nil)))
(should (equal (iso8601-parse-duration "PT1M")
'(0 1 0 0 0 0 nil nil nil 0)))
'(0 1 0 0 0 0 nil nil nil)))
(should (equal (iso8601-parse-duration "P0003-06-04T12:30:05")
'(5 30 12 4 6 3 nil nil nil 0))))
'(5 30 12 4 6 3 nil nil nil))))
(ert-deftest test-iso8601-invalid ()
(should-not (iso8601-valid-p " 2008-03-02T13:47:30-01"))
@ -94,149 +94,149 @@
(ert-deftest test-iso8601-intervals ()
(should (equal
(iso8601-parse-interval "2007-03-01T13:00:00Z/2008-05-11T15:30:00Z")
'((0 0 13 1 3 2007 nil nil 0 0)
(0 30 15 11 5 2008 nil nil 0 0)
'((0 0 13 1 3 2007 nil nil 0)
(0 30 15 11 5 2008 nil nil 0)
;; Hm... can't really use decode-time for time differences...
(0 30 2 14 3 1971 0 nil 0 0))))
(0 30 2 14 3 1971 0 nil 0))))
(should (equal (iso8601-parse-interval "2007-03-01T13:00:00Z/P1Y2M10DT2H30M")
'((0 0 13 1 3 2007 nil nil 0 0)
(0 30 15 11 5 2008 nil nil 0 0)
(0 30 2 10 2 1 nil nil nil 0))))
'((0 0 13 1 3 2007 nil nil 0)
(0 30 15 11 5 2008 nil nil 0)
(0 30 2 10 2 1 nil nil nil))))
(should (equal (iso8601-parse-interval "P1Y2M10DT2H30M/2008-05-11T15:30:00Z")
'((0 0 13 1 3 2007 nil nil 0 0)
(0 30 15 11 5 2008 nil nil 0 0)
(0 30 2 10 2 1 nil nil nil 0)))))
'((0 0 13 1 3 2007 nil nil 0)
(0 30 15 11 5 2008 nil nil 0)
(0 30 2 10 2 1 nil nil nil)))))
(ert-deftest standard-test-dates ()
(should (equal (iso8601-parse-date "19850412")
'(nil nil nil 12 4 1985 nil nil nil nil)))
'(nil nil nil 12 4 1985 nil nil nil)))
(should (equal (iso8601-parse-date "1985-04-12")
'(nil nil nil 12 4 1985 nil nil nil nil)))
'(nil nil nil 12 4 1985 nil nil nil)))
(should (equal (iso8601-parse-date "1985102")
'(nil nil nil 12 4 1985 nil nil nil nil)))
'(nil nil nil 12 4 1985 nil nil nil)))
(should (equal (iso8601-parse-date "1985-102")
'(nil nil nil 12 4 1985 nil nil nil nil)))
'(nil nil nil 12 4 1985 nil nil nil)))
(should (equal (iso8601-parse-date "1985W155")
'(nil nil nil 12 4 1985 nil nil nil nil)))
'(nil nil nil 12 4 1985 nil nil nil)))
(should (equal (iso8601-parse-date "1985-W15-5")
'(nil nil nil 12 4 1985 nil nil nil nil)))
'(nil nil nil 12 4 1985 nil nil nil)))
(should (equal (iso8601-parse-date "1985W15")
'(nil nil nil 7 4 1985 nil nil nil nil)))
'(nil nil nil 7 4 1985 nil nil nil)))
(should (equal (iso8601-parse-date "1985-W15")
'(nil nil nil 7 4 1985 nil nil nil nil)))
'(nil nil nil 7 4 1985 nil nil nil)))
(should (equal (iso8601-parse-date "1985-04")
'(nil nil nil nil 4 1985 nil nil nil nil)))
'(nil nil nil nil 4 1985 nil nil nil)))
(should (equal (iso8601-parse-date "1985")
'(nil nil nil nil nil 1985 nil nil nil nil)))
'(nil nil nil nil nil 1985 nil nil nil)))
(should (equal (iso8601-parse-date "+1985-04-12")
'(nil nil nil 12 4 1985 nil nil nil nil)))
'(nil nil nil 12 4 1985 nil nil nil)))
(should (equal (iso8601-parse-date "+19850412")
'(nil nil nil 12 4 1985 nil nil nil nil))))
'(nil nil nil 12 4 1985 nil nil nil))))
(ert-deftest standard-test-time-of-day-local-time ()
(should (equal (iso8601-parse-time "152746")
'(46 27 15 nil nil nil nil nil nil 0)))
'(46 27 15 nil nil nil nil nil nil)))
(should (equal (iso8601-parse-time "15:27:46")
'(46 27 15 nil nil nil nil nil nil 0)))
'(46 27 15 nil nil nil nil nil nil)))
(should (equal (iso8601-parse-time "1528")
'(0 28 15 nil nil nil nil nil nil 0)))
'(0 28 15 nil nil nil nil nil nil)))
(should (equal (iso8601-parse-time "15:28")
'(0 28 15 nil nil nil nil nil nil 0)))
'(0 28 15 nil nil nil nil nil nil)))
(should (equal (iso8601-parse-time "15")
'(0 0 15 nil nil nil nil nil nil 0))))
'(0 0 15 nil nil nil nil nil nil))))
(ert-deftest standard-test-time-of-day-fractions ()
;; decoded-time doesn't support sub-second times.
;; (should (equal (iso8601-parse-time "152735,5")
;; '(46 27 15 nil nil nil nil nil nil (5 . 10))))
;; '(46 27 15 nil nil nil nil nil nil)))
;; (should (equal (iso8601-parse-time "15:27:35,5")
;; '(46 27 15 nil nil nil nil nil nil (5 . 10))))
;; '(46 27 15 nil nil nil nil nil nil)))
)
(ert-deftest standard-test-time-of-day-beginning-of-day ()
(should (equal (iso8601-parse-time "000000")
'(0 0 0 nil nil nil nil nil nil 0)))
'(0 0 0 nil nil nil nil nil nil)))
(should (equal (iso8601-parse-time "00:00:00")
'(0 0 0 nil nil nil nil nil nil 0)))
'(0 0 0 nil nil nil nil nil nil)))
(should (equal (iso8601-parse-time "0000")
'(0 0 0 nil nil nil nil nil nil 0)))
'(0 0 0 nil nil nil nil nil nil)))
(should (equal (iso8601-parse-time "00:00")
'(0 0 0 nil nil nil nil nil nil 0))))
'(0 0 0 nil nil nil nil nil nil))))
(ert-deftest standard-test-time-of-day-utc ()
(should (equal (iso8601-parse-time "232030Z")
'(30 20 23 nil nil nil nil nil 0 0)))
'(30 20 23 nil nil nil nil nil 0)))
(should (equal (iso8601-parse-time "23:20:30Z")
'(30 20 23 nil nil nil nil nil 0 0)))
'(30 20 23 nil nil nil nil nil 0)))
(should (equal (iso8601-parse-time "2320Z")
'(0 20 23 nil nil nil nil nil 0 0)))
'(0 20 23 nil nil nil nil nil 0)))
(should (equal (iso8601-parse-time "23:20Z")
'(0 20 23 nil nil nil nil nil 0 0)))
'(0 20 23 nil nil nil nil nil 0)))
(should (equal (iso8601-parse-time "23Z")
'(0 0 23 nil nil nil nil nil 0 0))))
'(0 0 23 nil nil nil nil nil 0))))
(ert-deftest standard-test-time-of-day-zone ()
(should (equal (iso8601-parse-time "152746+0100")
'(46 27 15 nil nil nil nil nil 3600 0)))
'(46 27 15 nil nil nil nil nil 3600)))
(should (equal (iso8601-parse-time "15:27:46+0100")
'(46 27 15 nil nil nil nil nil 3600 0)))
'(46 27 15 nil nil nil nil nil 3600)))
(should (equal (iso8601-parse-time "152746+01")
'(46 27 15 nil nil nil nil nil 3600 0)))
'(46 27 15 nil nil nil nil nil 3600)))
(should (equal (iso8601-parse-time "15:27:46+01")
'(46 27 15 nil nil nil nil nil 3600 0)))
'(46 27 15 nil nil nil nil nil 3600)))
(should (equal (iso8601-parse-time "152746-0500")
'(46 27 15 nil nil nil nil nil -18000 0)))
'(46 27 15 nil nil nil nil nil -18000)))
(should (equal (iso8601-parse-time "15:27:46-0500")
'(46 27 15 nil nil nil nil nil -18000 0)))
'(46 27 15 nil nil nil nil nil -18000)))
(should (equal (iso8601-parse-time "152746-05")
'(46 27 15 nil nil nil nil nil -18000 0)))
'(46 27 15 nil nil nil nil nil -18000)))
(should (equal (iso8601-parse-time "15:27:46-05")
'(46 27 15 nil nil nil nil nil -18000 0))))
'(46 27 15 nil nil nil nil nil -18000))))
(ert-deftest standard-test-date-and-time-of-day ()
(should (equal (iso8601-parse "19850412T101530")
'(30 15 10 12 4 1985 nil nil nil 0)))
'(30 15 10 12 4 1985 nil nil nil)))
(should (equal (iso8601-parse "1985-04-12T10:15:30")
'(30 15 10 12 4 1985 nil nil nil 0)))
'(30 15 10 12 4 1985 nil nil nil)))
(should (equal (iso8601-parse "1985102T235030Z")
'(30 50 23 12 4 1985 nil nil 0 0)))
'(30 50 23 12 4 1985 nil nil 0)))
(should (equal (iso8601-parse "1985-102T23:50:30Z")
'(30 50 23 12 4 1985 nil nil 0 0)))
'(30 50 23 12 4 1985 nil nil 0)))
(should (equal (iso8601-parse "1985W155T235030")
'(30 50 23 12 4 1985 nil nil nil 0)))
'(30 50 23 12 4 1985 nil nil nil)))
(should (equal (iso8601-parse "1985-W155T23:50:30")
'(30 50 23 12 4 1985 nil nil nil 0))))
'(30 50 23 12 4 1985 nil nil nil))))
(ert-deftest standard-test-interval ()
;; A time interval starting at 20 minutes and 50 seconds past 23
;; hours on 12 April 1985 and ending at 30 minutes past 10 hours on
;; 25 June 1985.
(should (equal (iso8601-parse-interval "19850412T232050Z/19850625T103000Z")
'((50 20 23 12 4 1985 nil nil 0 0)
(0 30 10 25 6 1985 nil nil 0 0)
(10 9 11 15 3 1970 0 nil 0 0))))
'((50 20 23 12 4 1985 nil nil 0)
(0 30 10 25 6 1985 nil nil 0)
(10 9 11 15 3 1970 0 nil 0))))
(should (equal (iso8601-parse-interval
"1985-04-12T23:20:50Z/1985-06-25T10:30:00Z")
'((50 20 23 12 4 1985 nil nil 0 0)
(0 30 10 25 6 1985 nil nil 0 0)
(10 9 11 15 3 1970 0 nil 0 0))))
'((50 20 23 12 4 1985 nil nil 0)
(0 30 10 25 6 1985 nil nil 0)
(10 9 11 15 3 1970 0 nil 0))))
;; A time interval starting at 12 April 1985 and ending on 25 June
;; 1985.
@ -251,41 +251,41 @@
;; A time interval of 2 years, 10 months, 15 days, 10 hours, 20
;; minutes and 30 seconds.
(should (equal (iso8601-parse-duration "P2Y10M15DT10H20M30S")
'(30 20 10 15 10 2 nil nil nil 0)))
'(30 20 10 15 10 2 nil nil nil)))
(should (equal (iso8601-parse-duration "P00021015T102030")
'(30 20 10 15 10 2 nil nil nil 0)))
'(30 20 10 15 10 2 nil nil nil)))
(should (equal (iso8601-parse-duration "P0002-10-15T10:20:30")
'(30 20 10 15 10 2 nil nil nil 0)))
'(30 20 10 15 10 2 nil nil nil)))
;; A time interval of 1 year and 6 months.
(should (equal (iso8601-parse-duration "P1Y6M")
'(0 0 0 0 6 1 nil nil nil 0)))
'(0 0 0 0 6 1 nil nil nil)))
(should (equal (iso8601-parse-duration "P0001-06")
'(nil nil nil nil 6 1 nil nil nil nil)))
'(nil nil nil nil 6 1 nil nil nil)))
;; A time interval of seventy-two hours.
(should (equal (iso8601-parse-duration "PT72H")
'(0 0 72 0 0 0 nil nil nil 0)))
'(0 0 72 0 0 0 nil nil nil)))
;; Defined by start and duration
;; A time interval of 1 year, 2 months, 15 days and 12 hours,
;; beginning on 12 April 1985 at 20 minutes past 23 hours.
(should (equal (iso8601-parse-interval "19850412T232000/P1Y2M15DT12H")
'((0 20 23 12 4 1985 nil nil nil 0)
(0 20 11 28 6 1986 nil nil nil 0)
(0 0 12 15 2 1 nil nil nil 0))))
'((0 20 23 12 4 1985 nil nil nil)
(0 20 11 28 6 1986 nil nil nil)
(0 0 12 15 2 1 nil nil nil))))
(should (equal (iso8601-parse-interval "1985-04-12T23:20:00/P1Y2M15DT12H")
'((0 20 23 12 4 1985 nil nil nil 0)
(0 20 11 28 6 1986 nil nil nil 0)
(0 0 12 15 2 1 nil nil nil 0))))
'((0 20 23 12 4 1985 nil nil nil)
(0 20 11 28 6 1986 nil nil nil)
(0 0 12 15 2 1 nil nil nil))))
;; Defined by duration and end
;; A time interval of 1 year, 2 months, 15 days and 12 hours, ending
;; on 12 April 1985 at 20 minutes past 23 hour.
(should (equal (iso8601-parse-interval "P1Y2M15DT12H/19850412T232000")
'((0 20 11 28 1 1984 nil nil nil 0)
(0 20 23 12 4 1985 nil nil nil 0)
(0 0 12 15 2 1 nil nil nil 0)))))
'((0 20 11 28 1 1984 nil nil nil)
(0 20 23 12 4 1985 nil nil nil)
(0 0 12 15 2 1 nil nil nil)))))
;;; iso8601-tests.el ends here

View file

@ -28,23 +28,23 @@
(ert-deftest parse-time-tests ()
(should (equal (parse-time-string "Mon, 22 Feb 2016 19:35:42 +0100")
'(42 35 19 22 2 2016 1 -1 3600 0)))
'(42 35 19 22 2 2016 1 -1 3600)))
(should (equal (parse-time-string "22 Feb 2016 19:35:42 +0100")
'(42 35 19 22 2 2016 nil -1 3600 0)))
'(42 35 19 22 2 2016 nil -1 3600)))
(should (equal (parse-time-string "22 Feb 2016 +0100")
'(nil nil nil 22 2 2016 nil -1 3600 nil)))
'(nil nil nil 22 2 2016 nil -1 3600)))
(should (equal (parse-time-string "Mon, 22 Feb 16 19:35:42 +0100")
'(42 35 19 22 2 2016 1 -1 3600 0)))
'(42 35 19 22 2 2016 1 -1 3600)))
(should (equal (parse-time-string "Mon, 22 February 2016 19:35:42 +0100")
'(42 35 19 22 2 2016 1 -1 3600 0)))
'(42 35 19 22 2 2016 1 -1 3600)))
(should (equal (parse-time-string "Mon, 22 feb 2016 19:35:42 +0100")
'(42 35 19 22 2 2016 1 -1 3600 0)))
'(42 35 19 22 2 2016 1 -1 3600)))
(should (equal (parse-time-string "Monday, 22 february 2016 19:35:42 +0100")
'(42 35 19 22 2 2016 1 -1 3600 0)))
'(42 35 19 22 2 2016 1 -1 3600)))
(should (equal (parse-time-string "Monday, 22 february 2016 19:35:42 PST")
'(42 35 19 22 2 2016 1 nil -28800 0)))
'(42 35 19 22 2 2016 1 nil -28800)))
(should (equal (parse-time-string "Friday, 21 Sep 2018 13:47:58 PDT")
'(58 47 13 21 9 2018 5 t -25200 0)))
'(58 47 13 21 9 2018 5 t -25200)))
(should (equal (format-time-string
"%Y-%m-%d %H:%M:%S"
(parse-iso8601-time-string "1998-09-12T12:21:54-0200") t)

View file

@ -40,25 +40,31 @@
(7879679999900 . 100000)
(78796799999999999999 . 1000000000000)))
;; UTC.
(let ((subsec (time-subtract (time-convert look t)
(time-convert look 'integer))))
(let ((sec (time-add 59 (time-subtract (time-convert look t)
(time-convert look 'integer)))))
(should (string-equal
(format-time-string "%Y-%m-%d %H:%M:%S.%3N %z" look t)
"1972-06-30 23:59:59.999 +0000"))
(should (equal (decode-time look t)
(list 59 59 23 30 6 1972 5 nil 0 subsec)))
(should (equal (decode-time look t 'integer)
'(59 59 23 30 6 1972 5 nil 0)))
(should (equal (decode-time look t t)
(list sec 59 23 30 6 1972 5 nil 0)))
;; "UTC0".
(should (string-equal
(format-time-string format look "UTC0")
"1972-06-30 23:59:59.999 +0000 (UTC)"))
(should (equal (decode-time look "UTC0")
(list 59 59 23 30 6 1972 5 nil 0 subsec)))
(should (equal (decode-time look "UTC0" 'integer)
'(59 59 23 30 6 1972 5 nil 0)))
(should (equal (decode-time look "UTC0" t)
(list sec 59 23 30 6 1972 5 nil 0)))
;; Negative UTC offset, as a Lisp list.
(should (string-equal
(format-time-string format look '(-28800 "PST"))
"1972-06-30 15:59:59.999 -0800 (PST)"))
(should (equal (decode-time look '(-28800 "PST"))
(list 59 59 15 30 6 1972 5 nil -28800 subsec)))
(should (equal (decode-time look '(-28800 "PST") 'integer)
'(59 59 15 30 6 1972 5 nil -28800)))
(should (equal (decode-time look '(-28800 "PST") t)
(list sec 59 15 30 6 1972 5 nil -28800)))
;; Negative UTC offset, as a Lisp integer.
(should (string-equal
(format-time-string format look -28800)
@ -67,14 +73,18 @@
(if (eq system-type 'windows-nt)
"1972-06-30 15:59:59.999 -0800 (ZZZ)"
"1972-06-30 15:59:59.999 -0800 (-08)")))
(should (equal (decode-time look -28800)
(list 59 59 15 30 6 1972 5 nil -28800 subsec)))
(should (equal (decode-time look -28800 'integer)
'(59 59 15 30 6 1972 5 nil -28800)))
(should (equal (decode-time look -28800 t)
(list sec 59 15 30 6 1972 5 nil -28800)))
;; Positive UTC offset that is not an hour multiple, as a string.
(should (string-equal
(format-time-string format look "IST-5:30")
"1972-07-01 05:29:59.999 +0530 (IST)"))
(should (equal (decode-time look "IST-5:30")
(list 59 29 5 1 7 1972 6 nil 19800 subsec)))))))
(should (equal (decode-time look "IST-5:30" 'integer)
'(59 29 5 1 7 1972 6 nil 19800)))
(should (equal (decode-time look "IST-5:30" t)
(list sec 29 5 1 7 1972 6 nil 19800)))))))
(ert-deftest decode-then-encode-time ()
(let ((time-values (list 0 -2 1 0.0 -0.0 -2.0 1.0
@ -87,11 +97,13 @@
(cons (1+ most-positive-fixnum) 1000000000000)
(cons 1000000000000 (1+ most-positive-fixnum)))))
(dolist (a time-values)
(let* ((d (ignore-errors (decode-time a t)))
(let* ((d (ignore-errors (decode-time a t t)))
(d-integer (ignore-errors (decode-time a t 'integer)))
(e (if d (encode-time d)))
(diff (float-time (time-subtract a e))))
(should (or (not d)
(and (<= 0 diff) (< diff 1))))))))
(e-integer (if d-integer (encode-time d-integer))))
(should (or (not d) (time-equal-p a e)))
(should (or (not d-integer) (time-equal-p (time-convert a 'integer)
e-integer)))))))
;;; This should not dump core.
(ert-deftest format-time-string-with-outlandish-zone ()
@ -151,7 +163,7 @@
(ert-deftest encode-time-dst-numeric-zone ()
"Check for Bug#35502."
(should (time-equal-p
(encode-time '(29 31 17 30 4 2019 2 t 7200 0))
(encode-time '(29 31 17 30 4 2019 2 t 7200))
'(23752 27217))))
(ert-deftest float-time-precision ()