diff --git a/lisp/calc/calc-forms.el b/lisp/calc/calc-forms.el index 6d70126c098..a2f66968665 100644 --- a/lisp/calc/calc-forms.el +++ b/lisp/calc/calc-forms.el @@ -709,6 +709,10 @@ as measured in the number of days before December 31, 1 BC (Gregorian).") "The beginning of the Julian date calendar, as measured in the integer number of days before December 31, 1 BC (Gregorian).") +(defconst math-unix-epoch 719163 + "The beginning of Unix time: days from December 31, 1 BC (Gregorian) +to Jan 1, 1970 AD.") + (defun math-format-date-part (x) (cond ((stringp x) x) @@ -730,7 +734,8 @@ as measured in the integer number of days before December 31, 1 BC (Gregorian)." (math-floor math-fd-date) math-julian-date-beginning-int))) ((eq x 'U) - (math-format-number (nth 1 (math-date-parts math-fd-date 719164)))) + (math-format-number (nth 1 (math-date-parts math-fd-date + math-unix-epoch)))) ((memq x '(IYYY Iww w)) (progn (or math-fd-iso-dt @@ -1173,7 +1178,7 @@ as measured in the integer number of days before December 31, 1 BC (Gregorian)." (setq num (math-match-substring math-pd-str 0) math-pd-str (substring math-pd-str (match-end 0)) num (math-date-to-dt - (math-add 719164 + (math-add math-unix-epoch (math-div (math-read-number num) '(float 864 2)))) hour (nth 3 num) @@ -1434,11 +1439,11 @@ as measured in the integer number of days before December 31, 1 BC (Gregorian)." (defun calcFunc-unixtime (date &optional zone) (if (math-realp date) (progn - (setq date (math-add 719163 (math-div date '(float 864 2)))) + (setq date (math-add math-unix-epoch (math-div date '(float 864 2)))) (list 'date (math-sub date (math-div (calcFunc-tzone zone date) '(float 864 2))))) (if (eq (car date) 'date) - (math-add (nth 1 (math-date-parts (nth 1 date) 719163)) + (math-add (nth 1 (math-date-parts (nth 1 date) math-unix-epoch)) (calcFunc-tzone zone date)) (math-reject-arg date 'datep)))) diff --git a/test/lisp/calc/calc-tests.el b/test/lisp/calc/calc-tests.el index 4dded007f79..0df96a0e2db 100644 --- a/test/lisp/calc/calc-tests.el +++ b/test/lisp/calc/calc-tests.el @@ -534,6 +534,46 @@ An existing calc stack is reused, otherwise a new one is created." ) )) +(ert-deftest calc-unix-date () + (let* ((d-1970-01-01 (math-parse-date "1970-01-01")) + (d-2020-09-07 (math-parse-date "2020-09-07")) + (d-1991-01-09-0600 (math-parse-date "1991-01-09 06:00"))) + ;; calcFunc-unixtime (command "t U") converts a date value to Unix time, + ;; and a number to a date. + (should (equal d-1970-01-01 '(date 719163))) + (should (equal (calcFunc-unixtime d-1970-01-01 0) 0)) + (should (equal (calc-tests--calc-to-number (cadr (calcFunc-unixtime 0 0))) + (cadr d-1970-01-01))) + (should (equal (calcFunc-unixtime d-2020-09-07 0) + (* (- (cadr d-2020-09-07) + (cadr d-1970-01-01)) + 86400))) + (should (equal (calcFunc-unixtime d-1991-01-09-0600 0) + 663400800)) + (should (equal (calc-tests--calc-to-number + (cadr (calcFunc-unixtime 663400800 0))) + 726841.25)) + + (let ((calc-date-format '(U))) + ;; Test parsing Unix time. + (should (equal (calc-tests--calc-to-number + (cadr (math-parse-date "0"))) + 719163)) + (should (equal (calc-tests--calc-to-number + (cadr (math-parse-date "469324800"))) + (+ 719163 (/ 469324800 86400)))) + (should (equal (calc-tests--calc-to-number + (cadr (math-parse-date "663400800"))) + 726841.25)) + + ;; Test formatting Unix time. + (should (equal (math-format-date d-1970-01-01) "0")) + (should (equal (math-format-date d-2020-09-07) + (number-to-string (* (- (cadr d-2020-09-07) + (cadr d-1970-01-01)) + 86400)))) + (should (equal (math-format-date d-1991-01-09-0600) "663400800"))))) + (provide 'calc-tests) ;;; calc-tests.el ends here