X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/2d3c9015c70fd05ac1bec42cc59d57c3fb6b82b5..294127e7d59a5d23a32561716a1b192db410e12f:/lisp/calendar/time-date.el diff --git a/lisp/calendar/time-date.el b/lisp/calendar/time-date.el index b04cfcd9fe..bb7e97ea7f 100644 --- a/lisp/calendar/time-date.el +++ b/lisp/calendar/time-date.el @@ -1,6 +1,6 @@ ;;; time-date.el --- Date and time handling functions -;; Copyright (C) 1998-2014 Free Software Foundation, Inc. +;; Copyright (C) 1998-2015 Free Software Foundation, Inc. ;; Author: Lars Magne Ingebrigtsen ;; Masanobu Umeda @@ -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: @@ -44,7 +43,7 @@ The value of the last form in BODY is returned. Each element of the list VARLIST is a list of the form \(HIGH-SYMBOL LOW-SYMBOL MICRO-SYMBOL [PICO-SYMBOL [TYPE-SYMBOL]] TIME-VALUE). -The time value TIME-VALUE is decoded and the result it bound to +The time value TIME-VALUE is decoded and the result is bound to the symbols HIGH-SYMBOL, LOW-SYMBOL and MICRO-SYMBOL. The optional PICO-SYMBOL is bound to the picoseconds part. @@ -66,7 +65,32 @@ list (HIGH LOW MICRO PICO)." (pop elt))) (time-value (car elt)) (gensym (make-symbol "time"))) - `(let* ,(append `((,gensym ,time-value) + `(let* ,(append `((,gensym (or ,time-value (current-time))) + (,gensym + (cond + ((integerp ,gensym) + (list (ash ,gensym -16) + (logand ,gensym 65535))) + ((floatp ,gensym) + (let* ((usec (* 1000000 (mod ,gensym 1))) + (ps (round (* 1000000 (mod usec 1)))) + (us (floor usec)) + (lo (floor (mod ,gensym 65536))) + (hi (floor ,gensym 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))) + (t ,gensym))) (,high (pop ,gensym)) ,low ,micro) (when pico `(,pico)) @@ -108,6 +132,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 (and (fboundp 'time-add) (subrp (symbol-function 'time-add))) + (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") @@ -119,13 +147,20 @@ it is assumed that PICO was omitted and should be treated as zero." (defun date-to-time (date) "Parse a string DATE that represents a date-time and return a time value. If DATE lacks timezone information, GMT is assumed." - (condition-case () + (condition-case err (apply 'encode-time (parse-time-string date)) - (error (condition-case () - (apply 'encode-time - (parse-time-string - (timezone-make-date-arpa-standard date))) - (error (error "Invalid date: %s" date)))))) + (error + (let ((overflow-error '(error "Specified time is not representable"))) + (if (equal err overflow-error) + (apply 'signal err) + (condition-case err + (apply 'encode-time + (parse-time-string + (timezone-make-date-arpa-standard date))) + (error + (if (equal err overflow-error) + (apply 'signal err) + (error "Invalid date: %s" date))))))))) ;; Bit of a mess. Emacs has float-time since at least 21.1. ;; This file is synced to Gnus, and XEmacs packages may have been written @@ -140,56 +175,28 @@ If DATE lacks timezone information, GMT is assumed." (or (featurep 'emacs) (and (fboundp 'float-time) (subrp (symbol-function 'float-time))) - (defun time-to-seconds (time) - "Convert time value TIME to a floating point number." - (with-decoded-time-value ((high low micro pico type time)) - (+ (* 1.0 high 65536) + (defun time-to-seconds (&optional time) + "Convert optional value TIME to a floating point number. +TIME defaults to the current time." + (with-decoded-time-value ((high low micro pico type + (or time (current-time)))) + (+ (* high 65536.0) low (/ (+ (* micro 1e6) pico) 1e12)))))) ;;;###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) @@ -198,53 +205,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. +;; 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") + +(eval-and-compile + (when (not (and (fboundp 'time-add) (subrp (symbol-function 'time-add)))) + + (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))) - -;;;###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))) + (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) @@ -265,11 +290,9 @@ DATE1 and DATE2 should be date-time strings." (not (zerop (% year 100)))) (zerop (% year 400)))) -;;;###autoload -(defun time-to-day-in-year (time) - "Return the day number within the year corresponding to TIME." - (let* ((tim (decode-time time)) - (month (nth 4 tim)) +(defun time-date--day-in-year (tim) + "Return the day number within the year corresponding to the decoded time TIM." + (let* ((month (nth 4 tim)) (day (nth 3 tim)) (year (nth 5 tim)) (day-of-year (+ day (* 31 (1- month))))) @@ -279,6 +302,11 @@ DATE1 and DATE2 should be date-time strings." (setq day-of-year (1+ day-of-year)))) day-of-year)) +;;;###autoload +(defun time-to-day-in-year (time) + "Return the day number within the year corresponding to TIME." + (time-date--day-in-year (decode-time time))) + ;;;###autoload (defun time-to-days (time) "The number of days between the Gregorian date 0001-12-31bce and TIME. @@ -286,7 +314,7 @@ TIME should be a time value. The Gregorian date Sunday, December 31, 1bce is imaginary." (let* ((tim (decode-time time)) (year (nth 5 tim))) - (+ (time-to-day-in-year time) ; Days this year + (+ (time-date--day-in-year tim) ; Days this year (* 365 (1- year)) ; + Days in prior years (/ (1- year) 4) ; + Julian leap years (- (/ (1- year) 100)) ; - century years