From 0921dbc3ab4dcc6b291ef45e46a24b322bbcb885 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Sun, 16 Nov 2014 20:38:15 -0800 Subject: Improve time stamp handling, and be more consistent about it. This implements a suggestion made in: http://lists.gnu.org/archive/html/emacs-devel/2014-10/msg00587.html Among other things, this means timer.el no longer needs to autoload the time-date module. * doc/lispref/os.texi (Time of Day, Time Conversion, Time Parsing) (Processor Run Time, Time Calculations): Document the new behavior, plus be clearer about the old behavior. (Idle Timers): Take advantage of new functionality. * etc/NEWS: Document the changes. * lisp/allout-widgets.el (allout-elapsed-time-seconds): Doc fix. * lisp/arc-mode.el (archive-ar-summarize): * lisp/calendar/time-date.el (seconds-to-time, days-to-time, time-since): * lisp/emacs-lisp/timer.el (timer-relative-time, timer-event-handler) (run-at-time, with-timeout-suspend, with-timeout-unsuspend): * lisp/net/tramp.el (tramp-time-less-p, tramp-time-subtract): * lisp/proced.el (proced-time-lessp): * lisp/timezone.el (timezone-time-from-absolute): * lisp/type-break.el (type-break-schedule, type-break-time-sum): Simplify by using new functionality. * lisp/calendar/cal-dst.el (calendar-next-time-zone-transition): Do not return time values in obsolete and undocumented (HI . LO) format; use (HI LO) instead. * lisp/calendar/time-date.el (with-decoded-time-value): Treat 'nil' as current time. This is mostly for XEmacs. (encode-time-value, with-decoded-time-value): Obsolete. (time-add, time-subtract, time-less-p): Use no-op autoloads, for XEmacs. Define only if XEmacs, as they're now C builtins in Emacs. * lisp/ldefs-boot.el: Update to match new time-date.el * lisp/proced.el: Do not require time-date. * src/editfns.c (invalid_time): New function. Use it instead of 'error ("Invalid time specification")'. (time_add, time_subtract, time_arith, Ftime_add, Ftime_less_p) (decode_float_time, lisp_to_timespec, lisp_time_struct): New functions. (make_time_tail, make_time): Remove. All uses changed to use new functions or plain list4i. (disassemble_lisp_time): Return effective length if successful. Check that LOW is an integer, if it's combined with other components. (decode_time_components): Decode into struct lisp_time, not struct timespec, so that we can support a wide set of times regardless of whether time_t is signed. Decode plain numbers as seconds since the Epoch, and nil as the current time. (lisp_time_argument, lisp_seconds_argument, Ffloat_time): Reimplement in terms of new functions. (Fencode_time): Just use list2i. (syms_of_editfns): Add time-add, time-subtract, time-less-p. * src/keyboard.c (decode_timer): Don't allow the new formats (floating point or nil) in timers. * src/systime.h (LO_TIME_BITS): New constant. Use it everywhere in place of the magic number '16'. (struct lisp_time): New type. (decode_time_components): Use it. (lisp_to_timespec): New decl. --- lisp/calendar/cal-dst.el | 1 + lisp/calendar/time-date.el | 158 +++++++++++++++++++++------------------------ 2 files changed, 76 insertions(+), 83 deletions(-) (limited to 'lisp/calendar') diff --git a/lisp/calendar/cal-dst.el b/lisp/calendar/cal-dst.el index e3cb690306e..2a9cdee301d 100644 --- a/lisp/calendar/cal-dst.el +++ b/lisp/calendar/cal-dst.el @@ -179,6 +179,7 @@ Return nil if no such transition can be found." (if (eq (car (current-time-zone probe)) hi-utc-diff) (setq hi probe) (setq lo probe))) + (setcdr hi (list (cdr hi))) hi)))) (autoload 'calendar-persian-to-absolute "cal-persia") diff --git a/lisp/calendar/time-date.el b/lisp/calendar/time-date.el index 82bc05f299f..100e856469a 100644 --- a/lisp/calendar/time-date.el +++ b/lisp/calendar/time-date.el @@ -30,10 +30,9 @@ ;; value equal to HIGH * 2^16 + LOW + USEC * 10^-6 + PSEC * 10^-12 ;; seconds, where missing components are treated as zero. HIGH can be ;; negative, either because the value is a time difference, or because -;; the machine supports negative time stamps that fall before the epoch. -;; The macro `with-decoded-time-value' and the function -;; `encode-time-value' make it easier to deal with these formats. -;; See `time-subtract' for an example of how to use them. +;; it represents a time stamp before the epoch. Typically, there are +;; more time values than the underlying system time type supports, +;; but the reverse can also be true. ;;; Code: @@ -71,6 +70,7 @@ list (HIGH LOW MICRO PICO)." ,low ,micro) (when pico `(,pico)) (when type `(,type))) + (or ,gensym (setq ,gensym (current-time))) (if (consp ,gensym) (progn (setq ,low (pop ,gensym)) @@ -108,6 +108,10 @@ it is assumed that PICO was omitted and should be treated as zero." ((eq type 3) (list high low micro pico)) ((null type) (encode-time-value high low micro 0 pico)))) +(when (featurep 'emacs) + (make-obsolete 'encode-time-value nil "25.1") + (make-obsolete 'with-decoded-time-value nil "25.1")) + (autoload 'parse-time-string "parse-time") (autoload 'timezone-make-date-arpa-standard "timezone") @@ -158,47 +162,17 @@ TIME defaults to the current time." ;;;###autoload (defun seconds-to-time (seconds) - "Convert SECONDS (a floating point number) to a time value." - (let* ((usec (* 1000000 (mod seconds 1))) - (ps (round (* 1000000 (mod usec 1)))) - (us (floor usec)) - (lo (floor (mod seconds 65536))) - (hi (floor seconds 65536))) - (if (eq ps 1000000) - (progn - (setq ps 0) - (setq us (1+ us)) - (if (eq us 1000000) - (progn - (setq us 0) - (setq lo (1+ lo)) - (if (eq lo 65536) - (progn - (setq lo 0) - (setq hi (1+ hi)))))))) - (list hi lo us ps))) - -;;;###autoload -(defun time-less-p (t1 t2) - "Return non-nil if time value T1 is earlier than time value T2." - (with-decoded-time-value ((high1 low1 micro1 pico1 type1 t1) - (high2 low2 micro2 pico2 type2 t2)) - (or (< high1 high2) - (and (= high1 high2) - (or (< low1 low2) - (and (= low1 low2) - (or (< micro1 micro2) - (and (= micro1 micro2) - (< pico1 pico2))))))))) + "Convert SECONDS to a time value." + (time-add 0 seconds)) ;;;###autoload (defun days-to-time (days) "Convert DAYS into a time value." - (let* ((seconds (* 1.0 days 60 60 24)) - (high (condition-case nil (floor (/ seconds 65536)) - (range-error most-positive-fixnum)))) - (list high (condition-case nil (floor (- seconds (* 1.0 high 65536))) - (range-error 65535))))) + (let ((time (condition-case nil (seconds-to-time (* 86400.0 days)) + (range-error (list most-positive-fixnum 65535))))) + (if (integerp days) + (setcdr (cdr time) nil)) + time)) ;;;###autoload (defun time-since (time) @@ -207,53 +181,71 @@ TIME should be either a time value or a date-time string." (when (stringp time) ;; Convert date strings to internal time. (setq time (date-to-time time))) - (time-subtract (current-time) time)) + (time-subtract nil time)) ;;;###autoload (defalias 'subtract-time 'time-subtract) -;;;###autoload -(defun time-subtract (t1 t2) - "Subtract two time values, T1 minus T2. -Return the difference in the format of a time value." - (with-decoded-time-value ((high low micro pico type t1) - (high2 low2 micro2 pico2 type2 t2)) - (setq high (- high high2) - low (- low low2) - micro (- micro micro2) - pico (- pico pico2) - type (max type type2)) - (when (< pico 0) - (setq micro (1- micro) - pico (+ pico 1000000))) - (when (< micro 0) - (setq low (1- low) - micro (+ micro 1000000))) - (when (< low 0) - (setq high (1- high) - low (+ low 65536))) - (encode-time-value high low micro pico type))) +;; These autoloads do nothing in Emacs 25, where the functions are builtin. +;;;###autoload(autoload 'time-add "time-date") +;;;###autoload(autoload 'time-subtract "time-date") +;;;###autoload(autoload 'time-less-p "time-date") -;;;###autoload -(defun time-add (t1 t2) - "Add two time values T1 and T2. One should represent a time difference." - (with-decoded-time-value ((high low micro pico type t1) - (high2 low2 micro2 pico2 type2 t2)) - (setq high (+ high high2) - low (+ low low2) - micro (+ micro micro2) - pico (+ pico pico2) - type (max type type2)) - (when (>= pico 1000000) - (setq micro (1+ micro) - pico (- pico 1000000))) - (when (>= micro 1000000) - (setq low (1+ low) - micro (- micro 1000000))) - (when (>= low 65536) - (setq high (1+ high) - low (- low 65536))) - (encode-time-value high low micro pico type))) +(eval-when-compile + (when (not (featurep 'emacs)) + + (defun time-add (t1 t2) + "Add two time values T1 and T2. One should represent a time difference." + (with-decoded-time-value ((high low micro pico type t1) + (high2 low2 micro2 pico2 type2 t2)) + (setq high (+ high high2) + low (+ low low2) + micro (+ micro micro2) + pico (+ pico pico2) + type (max type type2)) + (when (>= pico 1000000) + (setq micro (1+ micro) + pico (- pico 1000000))) + (when (>= micro 1000000) + (setq low (1+ low) + micro (- micro 1000000))) + (when (>= low 65536) + (setq high (1+ high) + low (- low 65536))) + (encode-time-value high low micro pico type))) + + (defun time-subtract (t1 t2) + "Subtract two time values, T1 minus T2. +Return the difference in the format of a time value." + (with-decoded-time-value ((high low micro pico type t1) + (high2 low2 micro2 pico2 type2 t2)) + (setq high (- high high2) + low (- low low2) + micro (- micro micro2) + pico (- pico pico2) + type (max type type2)) + (when (< pico 0) + (setq micro (1- micro) + pico (+ pico 1000000))) + (when (< micro 0) + (setq low (1- low) + micro (+ micro 1000000))) + (when (< low 0) + (setq high (1- high) + low (+ low 65536))) + (encode-time-value high low micro pico type))) + + (defun time-less-p (t1 t2) + "Return non-nil if time value T1 is earlier than time value T2." + (with-decoded-time-value ((high1 low1 micro1 pico1 type1 t1) + (high2 low2 micro2 pico2 type2 t2)) + (or (< high1 high2) + (and (= high1 high2) + (or (< low1 low2) + (and (= low1 low2) + (or (< micro1 micro2) + (and (= micro1 micro2) + (< pico1 pico2))))))))))) ;;;###autoload (defun date-to-day (date) -- cgit v1.2.1