diff options
| author | Paul Eggert | 2019-08-20 17:34:03 -0700 |
|---|---|---|
| committer | Paul Eggert | 2019-08-20 17:36:46 -0700 |
| commit | 396ed88a50fba95cd3b989965defef0130a42c42 (patch) | |
| tree | 95b03c537acf8d65b6d894a283eccf9f1d31a1e8 | |
| parent | 7e2090ee80c9099ee953392444e1d73d10e973d4 (diff) | |
| download | emacs-396ed88a50fba95cd3b989965defef0130a42c42.tar.gz emacs-396ed88a50fba95cd3b989965defef0130a42c42.zip | |
Avoid some excess precision in time arithmetic
* doc/misc/emacs-mime.texi (time-date):
Adjust example to match new behavior.
* etc/NEWS: Mention this.
* lisp/calendar/time-date.el (decoded-time-add)
(decoded-time--alter-second):
Don’t lose underestimate precision of seconds component.
* src/bignum.c (mpz): Grow by 1.
* src/timefns.c (trillion_factor): New function.
(timeform_sub_ps_p): Remove.
(time_arith): Avoid unnecessarily-large hz, by reducing the hz
to a value no worse than the worse hz of the two arguments.
The result is always exact unless an error is signaled.
* test/src/timefns-tests.el (timefns-tests--decode-time):
New function.
(format-time-string-with-zone): Test (decode-time LOOK ZONE t)
resolution as well as its numeric value.
| -rw-r--r-- | doc/misc/emacs-mime.texi | 2 | ||||
| -rw-r--r-- | etc/NEWS | 4 | ||||
| -rw-r--r-- | lisp/calendar/time-date.el | 32 | ||||
| -rw-r--r-- | src/bignum.c | 5 | ||||
| -rw-r--r-- | src/bignum.h | 2 | ||||
| -rw-r--r-- | src/timefns.c | 106 | ||||
| -rw-r--r-- | test/src/timefns-tests.el | 44 |
7 files changed, 135 insertions, 60 deletions
diff --git a/doc/misc/emacs-mime.texi b/doc/misc/emacs-mime.texi index eb829b06124..131a358ba59 100644 --- a/doc/misc/emacs-mime.texi +++ b/doc/misc/emacs-mime.texi | |||
| @@ -1568,7 +1568,7 @@ Here's a bunch of time/date/second/day examples: | |||
| 1568 | 1568 | ||
| 1569 | (time-subtract '(905595714000000 . 1000000) | 1569 | (time-subtract '(905595714000000 . 1000000) |
| 1570 | '(905595593000000000 . 1000000000)) | 1570 | '(905595593000000000 . 1000000000)) |
| 1571 | @result{} (121000000000 . 1000000000) | 1571 | @result{} (121000000 . 1000000) |
| 1572 | 1572 | ||
| 1573 | (days-between "Sat Sep 12 12:21:54 1998 +0200" | 1573 | (days-between "Sat Sep 12 12:21:54 1998 +0200" |
| 1574 | "Sat Sep 07 12:21:54 1998 +0200") | 1574 | "Sat Sep 07 12:21:54 1998 +0200") |
| @@ -2166,7 +2166,9 @@ end and duration). | |||
| 2166 | +++ | 2166 | +++ |
| 2167 | *** 'time-add', 'time-subtract', and 'time-less-p' now accept | 2167 | *** 'time-add', 'time-subtract', and 'time-less-p' now accept |
| 2168 | infinities and NaNs too, and propagate them or return nil like | 2168 | infinities and NaNs too, and propagate them or return nil like |
| 2169 | floating-point operators do. | 2169 | floating-point operators do. If both arguments are finite, these |
| 2170 | functions now return exact results instead of rounding in some cases, | ||
| 2171 | and they also avoid excess precision when that is easy. | ||
| 2170 | 2172 | ||
| 2171 | +++ | 2173 | +++ |
| 2172 | *** New function 'time-equal-p' compares time values for equality. | 2174 | *** New function 'time-equal-p' compares time values for equality. |
diff --git a/lisp/calendar/time-date.el b/lisp/calendar/time-date.el index f3d252f03c6..11bd469ae3b 100644 --- a/lisp/calendar/time-date.el +++ b/lisp/calendar/time-date.el | |||
| @@ -421,10 +421,13 @@ changes in daylight saving time are not taken into account." | |||
| 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 | ;; Time zone adjustments are basically the same as time adjustments. | 423 | ;; Time zone adjustments are basically the same as time adjustments. |
| 424 | (setq seconds (time-add (+ (* (or (decoded-time-hour delta) 0) 3600) | 424 | (setq seconds (time-convert (or (decoded-time-second delta) 0) t)) |
| 425 | (* (or (decoded-time-minute delta) 0) 60) | 425 | (setq seconds |
| 426 | (or (decoded-time-zone delta) 0)) | 426 | (time-add seconds |
| 427 | (or (decoded-time-second delta) 0))) | 427 | (time-convert (+ (* (or (decoded-time-hour delta) 0) 3600) |
| 428 | (* (or (decoded-time-minute delta) 0) 60) | ||
| 429 | (or (decoded-time-zone delta) 0)) | ||
| 430 | (cdr seconds)))) | ||
| 428 | 431 | ||
| 429 | (decoded-time--alter-second time seconds) | 432 | (decoded-time--alter-second time seconds) |
| 430 | time)) | 433 | time)) |
| @@ -461,11 +464,16 @@ changes in daylight saving time are not taken into account." | |||
| 461 | 464 | ||
| 462 | (defun decoded-time--alter-second (time seconds) | 465 | (defun decoded-time--alter-second (time seconds) |
| 463 | "Increase the time in TIME by SECONDS." | 466 | "Increase the time in TIME by SECONDS." |
| 464 | (let* ((secsperday 86400) | 467 | (let* ((time-sec (time-convert (or (decoded-time-second time) 0) t)) |
| 465 | (old (time-add (+ (* 3600 (or (decoded-time-hour time) 0)) | 468 | (time-hz (cdr time-sec)) |
| 466 | (* 60 (or (decoded-time-minute time) 0))) | 469 | (old (time-add time-sec |
| 467 | (or (decoded-time-second time) 0))) | 470 | (time-convert |
| 468 | (new (time-add old seconds))) | 471 | (+ (* 3600 (or (decoded-time-hour time) 0)) |
| 472 | (* 60 (or (decoded-time-minute time) 0))) | ||
| 473 | time-hz))) | ||
| 474 | (new (time-convert (time-add old seconds) t)) | ||
| 475 | (new-hz (cdr new)) | ||
| 476 | (secsperday (time-convert 86400 new-hz))) | ||
| 469 | ;; Hm... DST... | 477 | ;; Hm... DST... |
| 470 | (while (time-less-p new 0) | 478 | (while (time-less-p new 0) |
| 471 | (decoded-time--alter-day time nil) | 479 | (decoded-time--alter-day time nil) |
| @@ -474,8 +482,10 @@ changes in daylight saving time are not taken into account." | |||
| 474 | (decoded-time--alter-day time t) | 482 | (decoded-time--alter-day time t) |
| 475 | (setq new (time-subtract new secsperday))) | 483 | (setq new (time-subtract new secsperday))) |
| 476 | (let ((sec (time-convert new 'integer))) | 484 | (let ((sec (time-convert new 'integer))) |
| 477 | (setf (decoded-time-second time) (time-add (% sec 60) | 485 | (setf (decoded-time-second time) (time-add |
| 478 | (time-subtract new sec)) | 486 | (time-convert (% sec 60) new-hz) |
| 487 | (time-subtract | ||
| 488 | new (time-convert sec new-hz))) | ||
| 479 | (decoded-time-minute time) (% (/ sec 60) 60) | 489 | (decoded-time-minute time) (% (/ sec 60) 60) |
| 480 | (decoded-time-hour time) (/ sec 3600))))) | 490 | (decoded-time-hour time) (/ sec 3600))))) |
| 481 | 491 | ||
diff --git a/src/bignum.c b/src/bignum.c index 3883d3a3944..90b1ebea876 100644 --- a/src/bignum.c +++ b/src/bignum.c | |||
| @@ -31,9 +31,10 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 31 | storage is exhausted. Admittedly this is not ideal. An mpz value | 31 | storage is exhausted. Admittedly this is not ideal. An mpz value |
| 32 | in a temporary is made permanent by mpz_swapping it with a bignum's | 32 | in a temporary is made permanent by mpz_swapping it with a bignum's |
| 33 | value. Although typically at most two temporaries are needed, | 33 | value. Although typically at most two temporaries are needed, |
| 34 | time_arith, rounddiv_q and rounding_driver each need four. */ | 34 | rounddiv_q and rounding_driver both need four and time_arith needs |
| 35 | five. */ | ||
| 35 | 36 | ||
| 36 | mpz_t mpz[4]; | 37 | mpz_t mpz[5]; |
| 37 | 38 | ||
| 38 | static void * | 39 | static void * |
| 39 | xrealloc_for_gmp (void *ptr, size_t ignore, size_t size) | 40 | xrealloc_for_gmp (void *ptr, size_t ignore, size_t size) |
diff --git a/src/bignum.h b/src/bignum.h index a9c7a0a09a8..9a32ffb0374 100644 --- a/src/bignum.h +++ b/src/bignum.h | |||
| @@ -41,7 +41,7 @@ struct Lisp_Bignum | |||
| 41 | mpz_t value; | 41 | mpz_t value; |
| 42 | } GCALIGNED_STRUCT; | 42 | } GCALIGNED_STRUCT; |
| 43 | 43 | ||
| 44 | extern mpz_t mpz[4]; | 44 | extern mpz_t mpz[5]; |
| 45 | 45 | ||
| 46 | extern void init_bignum (void); | 46 | extern void init_bignum (void); |
| 47 | extern Lisp_Object make_integer_mpz (void); | 47 | extern Lisp_Object make_integer_mpz (void); |
diff --git a/src/timefns.c b/src/timefns.c index 3b686eb2265..3c4c15b6576 100644 --- a/src/timefns.c +++ b/src/timefns.c | |||
| @@ -99,6 +99,22 @@ mpz_t ztrillion; | |||
| 99 | # endif | 99 | # endif |
| 100 | #endif | 100 | #endif |
| 101 | 101 | ||
| 102 | /* True if the nonzero Lisp integer HZ divides evenly into a trillion. */ | ||
| 103 | static bool | ||
| 104 | trillion_factor (Lisp_Object hz) | ||
| 105 | { | ||
| 106 | if (FASTER_TIMEFNS) | ||
| 107 | { | ||
| 108 | if (FIXNUMP (hz)) | ||
| 109 | return TRILLION % XFIXNUM (hz) == 0; | ||
| 110 | if (!FIXNUM_OVERFLOW_P (TRILLION)) | ||
| 111 | return false; | ||
| 112 | } | ||
| 113 | verify (TRILLION <= INTMAX_MAX); | ||
| 114 | intmax_t ihz; | ||
| 115 | return integer_to_intmax (hz, &ihz) && TRILLION % ihz == 0; | ||
| 116 | } | ||
| 117 | |||
| 102 | /* Return a struct timeval that is roughly equivalent to T. | 118 | /* Return a struct timeval that is roughly equivalent to T. |
| 103 | Use the least timeval not less than T. | 119 | Use the least timeval not less than T. |
| 104 | Return an extremal value if the result would overflow. */ | 120 | Return an extremal value if the result would overflow. */ |
| @@ -681,18 +697,10 @@ enum timeform | |||
| 681 | TIMEFORM_HI_LO_US, /* seconds plus microseconds (HI LO US) */ | 697 | TIMEFORM_HI_LO_US, /* seconds plus microseconds (HI LO US) */ |
| 682 | TIMEFORM_NIL, /* current time in nanoseconds */ | 698 | TIMEFORM_NIL, /* current time in nanoseconds */ |
| 683 | TIMEFORM_HI_LO_US_PS, /* seconds plus micro and picoseconds (HI LO US PS) */ | 699 | TIMEFORM_HI_LO_US_PS, /* seconds plus micro and picoseconds (HI LO US PS) */ |
| 684 | /* These two should be last; see timeform_sub_ps_p. */ | ||
| 685 | TIMEFORM_FLOAT, /* time as a float */ | 700 | TIMEFORM_FLOAT, /* time as a float */ |
| 686 | TIMEFORM_TICKS_HZ /* fractional time: HI is ticks, LO is ticks per second */ | 701 | TIMEFORM_TICKS_HZ /* fractional time: HI is ticks, LO is ticks per second */ |
| 687 | }; | 702 | }; |
| 688 | 703 | ||
| 689 | /* True if Lisp times of form FORM can express sub-picosecond timestamps. */ | ||
| 690 | static bool | ||
| 691 | timeform_sub_ps_p (enum timeform form) | ||
| 692 | { | ||
| 693 | return TIMEFORM_FLOAT <= form; | ||
| 694 | } | ||
| 695 | |||
| 696 | /* From the valid form FORM and the time components HIGH, LOW, USEC | 704 | /* From the valid form FORM and the time components HIGH, LOW, USEC |
| 697 | and PSEC, generate the corresponding time value. If LOW is | 705 | and PSEC, generate the corresponding time value. If LOW is |
| 698 | floating point, the other components should be zero and FORM should | 706 | floating point, the other components should be zero and FORM should |
| @@ -1080,9 +1088,14 @@ time_arith (Lisp_Object a, Lisp_Object b, bool subtract) | |||
| 1080 | else | 1088 | else |
| 1081 | { | 1089 | { |
| 1082 | /* The plan is to decompose ta into na/da and tb into nb/db. | 1090 | /* The plan is to decompose ta into na/da and tb into nb/db. |
| 1083 | Start by computing da and db. */ | 1091 | Start by computing da and db, their minimum (which will be |
| 1092 | needed later) and the iticks temporary that will become | ||
| 1093 | available once only their minimum is needed. */ | ||
| 1084 | mpz_t const *da = bignum_integer (&mpz[1], ta.hz); | 1094 | mpz_t const *da = bignum_integer (&mpz[1], ta.hz); |
| 1085 | mpz_t const *db = bignum_integer (&mpz[2], tb.hz); | 1095 | mpz_t const *db = bignum_integer (&mpz[2], tb.hz); |
| 1096 | bool da_lt_db = mpz_cmp (*da, *db) < 0; | ||
| 1097 | mpz_t const *hzmin = da_lt_db ? da : db; | ||
| 1098 | mpz_t *iticks = &mpz[da_lt_db + 1]; | ||
| 1086 | 1099 | ||
| 1087 | /* The plan is to compute (na * (db/g) + nb * (da/g)) / lcm (da, db) | 1100 | /* The plan is to compute (na * (db/g) + nb * (da/g)) / lcm (da, db) |
| 1088 | where g = gcd (da, db). Start by computing g. */ | 1101 | where g = gcd (da, db). Start by computing g. */ |
| @@ -1090,34 +1103,83 @@ time_arith (Lisp_Object a, Lisp_Object b, bool subtract) | |||
| 1090 | mpz_gcd (*g, *da, *db); | 1103 | mpz_gcd (*g, *da, *db); |
| 1091 | 1104 | ||
| 1092 | /* fa = da/g, fb = db/g. */ | 1105 | /* fa = da/g, fb = db/g. */ |
| 1093 | mpz_t *fa = &mpz[1], *fb = &mpz[3]; | 1106 | mpz_t *fa = &mpz[4], *fb = &mpz[3]; |
| 1094 | mpz_tdiv_q (*fa, *da, *g); | 1107 | mpz_tdiv_q (*fa, *da, *g); |
| 1095 | mpz_tdiv_q (*fb, *db, *g); | 1108 | mpz_tdiv_q (*fb, *db, *g); |
| 1096 | 1109 | ||
| 1097 | /* FIXME: Maybe omit need for extra temp by computing fa * db here? */ | 1110 | /* ihz = fa * db. This is equal to lcm (da, db). */ |
| 1098 | 1111 | mpz_t *ihz = &mpz[0]; | |
| 1099 | /* hz = fa * db. This is equal to lcm (da, db). */ | 1112 | mpz_mul (*ihz, *fa, *db); |
| 1100 | mpz_mul (mpz[0], *fa, *db); | 1113 | |
| 1101 | hz = make_integer_mpz (); | 1114 | /* When warning about obsolete timestamps, if the smaller |
| 1115 | denominator comes from a non-(TICKS . HZ) timestamp and could | ||
| 1116 | generate a (TICKS . HZ) timestamp that would look obsolete, | ||
| 1117 | arrange for the result to have a higher HZ to avoid a | ||
| 1118 | spurious warning by a later consumer of this function's | ||
| 1119 | returned value. */ | ||
| 1120 | verify (1 << LO_TIME_BITS <= ULONG_MAX); | ||
| 1121 | if (WARN_OBSOLETE_TIMESTAMPS | ||
| 1122 | && (da_lt_db ? aform : bform) == TIMEFORM_FLOAT | ||
| 1123 | && (da_lt_db ? bform : aform) != TIMEFORM_TICKS_HZ | ||
| 1124 | && mpz_cmp_ui (*hzmin, 1) > 0 | ||
| 1125 | && mpz_cmp_ui (*hzmin, 1 << LO_TIME_BITS) < 0) | ||
| 1126 | { | ||
| 1127 | mpz_t *hzmin1 = &mpz[2 - da_lt_db]; | ||
| 1128 | mpz_set_ui (*hzmin1, 1 << LO_TIME_BITS); | ||
| 1129 | hzmin = hzmin1; | ||
| 1130 | } | ||
| 1102 | 1131 | ||
| 1103 | /* ticks = (fb * na) OPER (fa * nb), where OPER is + or -. | 1132 | /* iticks = (fb * na) OP (fa * nb), where OP is + or -. */ |
| 1104 | OP is the multiply-add or multiply-sub form of OPER. */ | 1133 | mpz_t const *na = bignum_integer (iticks, ta.ticks); |
| 1105 | mpz_t const *na = bignum_integer (&mpz[0], ta.ticks); | 1134 | mpz_mul (*iticks, *fb, *na); |
| 1106 | mpz_mul (mpz[0], *fb, *na); | ||
| 1107 | mpz_t const *nb = bignum_integer (&mpz[3], tb.ticks); | 1135 | mpz_t const *nb = bignum_integer (&mpz[3], tb.ticks); |
| 1108 | (subtract ? mpz_submul : mpz_addmul) (mpz[0], *fa, *nb); | 1136 | (subtract ? mpz_submul : mpz_addmul) (*iticks, *fa, *nb); |
| 1137 | |||
| 1138 | /* Normalize iticks/ihz by dividing both numerator and | ||
| 1139 | denominator by ig = gcd (iticks, ihz). However, if that | ||
| 1140 | would cause the denominator to become less than hzmin, | ||
| 1141 | rescale the denominator upwards from its ordinary value by | ||
| 1142 | multiplying numerator and denominator so that the denominator | ||
| 1143 | becomes at least hzmin. This rescaling avoids returning a | ||
| 1144 | timestamp that is less precise than both a and b, or a | ||
| 1145 | timestamp that looks obsolete when that might be a problem. */ | ||
| 1146 | mpz_t *ig = &mpz[3]; | ||
| 1147 | mpz_gcd (*ig, *iticks, *ihz); | ||
| 1148 | |||
| 1149 | if (!FASTER_TIMEFNS || mpz_cmp_ui (*ig, 1) > 0) | ||
| 1150 | { | ||
| 1151 | mpz_tdiv_q (*iticks, *iticks, *ig); | ||
| 1152 | mpz_tdiv_q (*ihz, *ihz, *ig); | ||
| 1153 | |||
| 1154 | if (!FASTER_TIMEFNS || mpz_cmp (*ihz, *hzmin) < 0) | ||
| 1155 | { | ||
| 1156 | /* Rescale straightforwardly. Although this might not | ||
| 1157 | yield the minimal denominator that preserves numeric | ||
| 1158 | value and is at least hzmin, calculating such a | ||
| 1159 | denominator would be too expensive because it would | ||
| 1160 | require testing multisets of factors of lcm (da, db). */ | ||
| 1161 | mpz_t *rescale = &mpz[3]; | ||
| 1162 | mpz_cdiv_q (*rescale, *hzmin, *ihz); | ||
| 1163 | mpz_mul (*iticks, *iticks, *rescale); | ||
| 1164 | mpz_mul (*ihz, *ihz, *rescale); | ||
| 1165 | } | ||
| 1166 | } | ||
| 1167 | hz = make_integer_mpz (); | ||
| 1168 | mpz_swap (mpz[0], *iticks); | ||
| 1109 | ticks = make_integer_mpz (); | 1169 | ticks = make_integer_mpz (); |
| 1110 | } | 1170 | } |
| 1111 | 1171 | ||
| 1112 | /* Return an integer if the timestamp resolution is 1, | 1172 | /* Return an integer if the timestamp resolution is 1, |
| 1113 | otherwise the (TICKS . HZ) form if !CURRENT_TIME_LIST or if | 1173 | otherwise the (TICKS . HZ) form if !CURRENT_TIME_LIST or if |
| 1114 | either input form supports timestamps that cannot be expressed | 1174 | either input used (TICKS . HZ) form or the result can't be expressed |
| 1115 | exactly in (HI LO US PS) form, otherwise the (HI LO US PS) form | 1175 | exactly in (HI LO US PS) form, otherwise the (HI LO US PS) form |
| 1116 | for backward compatibility. */ | 1176 | for backward compatibility. */ |
| 1117 | return (EQ (hz, make_fixnum (1)) | 1177 | return (EQ (hz, make_fixnum (1)) |
| 1118 | ? ticks | 1178 | ? ticks |
| 1119 | : (!CURRENT_TIME_LIST | 1179 | : (!CURRENT_TIME_LIST |
| 1120 | || timeform_sub_ps_p (aform) || timeform_sub_ps_p (bform)) | 1180 | || aform == TIMEFORM_TICKS_HZ |
| 1181 | || bform == TIMEFORM_TICKS_HZ | ||
| 1182 | || !trillion_factor (hz)) | ||
| 1121 | ? Fcons (ticks, hz) | 1183 | ? Fcons (ticks, hz) |
| 1122 | : ticks_hz_list4 (ticks, hz)); | 1184 | : ticks_hz_list4 (ticks, hz)); |
| 1123 | } | 1185 | } |
diff --git a/test/src/timefns-tests.el b/test/src/timefns-tests.el index 48d964d129c..3a18a4a24dd 100644 --- a/test/src/timefns-tests.el +++ b/test/src/timefns-tests.el | |||
| @@ -19,6 +19,12 @@ | |||
| 19 | 19 | ||
| 20 | (require 'ert) | 20 | (require 'ert) |
| 21 | 21 | ||
| 22 | (defun timefns-tests--decode-time (look zone decoded-time) | ||
| 23 | (should (equal (decode-time look zone t) decoded-time)) | ||
| 24 | (should (equal (decode-time look zone 'integer) | ||
| 25 | (cons (time-convert (car decoded-time) 'integer) | ||
| 26 | (cdr decoded-time))))) | ||
| 27 | |||
| 22 | ;;; Check format-time-string and decode-time with various TZ settings. | 28 | ;;; Check format-time-string and decode-time with various TZ settings. |
| 23 | ;;; Use only POSIX-compatible TZ values, since the tests should work | 29 | ;;; Use only POSIX-compatible TZ values, since the tests should work |
| 24 | ;;; even if tzdb is not in use. | 30 | ;;; even if tzdb is not in use. |
| @@ -40,31 +46,29 @@ | |||
| 40 | (7879679999900 . 100000) | 46 | (7879679999900 . 100000) |
| 41 | (78796799999999999999 . 1000000000000))) | 47 | (78796799999999999999 . 1000000000000))) |
| 42 | ;; UTC. | 48 | ;; UTC. |
| 43 | (let ((sec (time-add 59 (time-subtract (time-convert look t) | 49 | (let* ((look-ticks-hz (time-convert look t)) |
| 44 | (time-convert look 'integer))))) | 50 | (hz (cdr look-ticks-hz)) |
| 51 | (look-integer (time-convert look 'integer)) | ||
| 52 | (sec (time-add (time-convert 59 hz) | ||
| 53 | (time-subtract look-ticks-hz | ||
| 54 | (time-convert look-integer hz))))) | ||
| 45 | (should (string-equal | 55 | (should (string-equal |
| 46 | (format-time-string "%Y-%m-%d %H:%M:%S.%3N %z" look t) | 56 | (format-time-string "%Y-%m-%d %H:%M:%S.%3N %z" look t) |
| 47 | "1972-06-30 23:59:59.999 +0000")) | 57 | "1972-06-30 23:59:59.999 +0000")) |
| 48 | (should (equal (decode-time look t 'integer) | 58 | (timefns-tests--decode-time look t |
| 49 | '(59 59 23 30 6 1972 5 nil 0))) | 59 | (list sec 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))) | ||
| 52 | ;; "UTC0". | 60 | ;; "UTC0". |
| 53 | (should (string-equal | 61 | (should (string-equal |
| 54 | (format-time-string format look "UTC0") | 62 | (format-time-string format look "UTC0") |
| 55 | "1972-06-30 23:59:59.999 +0000 (UTC)")) | 63 | "1972-06-30 23:59:59.999 +0000 (UTC)")) |
| 56 | (should (equal (decode-time look "UTC0" 'integer) | 64 | (timefns-tests--decode-time look "UTC0" |
| 57 | '(59 59 23 30 6 1972 5 nil 0))) | 65 | (list sec 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))) | ||
| 60 | ;; Negative UTC offset, as a Lisp list. | 66 | ;; Negative UTC offset, as a Lisp list. |
| 61 | (should (string-equal | 67 | (should (string-equal |
| 62 | (format-time-string format look '(-28800 "PST")) | 68 | (format-time-string format look '(-28800 "PST")) |
| 63 | "1972-06-30 15:59:59.999 -0800 (PST)")) | 69 | "1972-06-30 15:59:59.999 -0800 (PST)")) |
| 64 | (should (equal (decode-time look '(-28800 "PST") 'integer) | 70 | (timefns-tests--decode-time look '(-28800 "PST") |
| 65 | '(59 59 15 30 6 1972 5 nil -28800))) | 71 | (list sec 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))) | ||
| 68 | ;; Negative UTC offset, as a Lisp integer. | 72 | ;; Negative UTC offset, as a Lisp integer. |
| 69 | (should (string-equal | 73 | (should (string-equal |
| 70 | (format-time-string format look -28800) | 74 | (format-time-string format look -28800) |
| @@ -73,18 +77,14 @@ | |||
| 73 | (if (eq system-type 'windows-nt) | 77 | (if (eq system-type 'windows-nt) |
| 74 | "1972-06-30 15:59:59.999 -0800 (ZZZ)" | 78 | "1972-06-30 15:59:59.999 -0800 (ZZZ)" |
| 75 | "1972-06-30 15:59:59.999 -0800 (-08)"))) | 79 | "1972-06-30 15:59:59.999 -0800 (-08)"))) |
| 76 | (should (equal (decode-time look -28800 'integer) | 80 | (timefns-tests--decode-time look -28800 |
| 77 | '(59 59 15 30 6 1972 5 nil -28800))) | 81 | (list sec 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))) | ||
| 80 | ;; Positive UTC offset that is not an hour multiple, as a string. | 82 | ;; Positive UTC offset that is not an hour multiple, as a string. |
| 81 | (should (string-equal | 83 | (should (string-equal |
| 82 | (format-time-string format look "IST-5:30") | 84 | (format-time-string format look "IST-5:30") |
| 83 | "1972-07-01 05:29:59.999 +0530 (IST)")) | 85 | "1972-07-01 05:29:59.999 +0530 (IST)")) |
| 84 | (should (equal (decode-time look "IST-5:30" 'integer) | 86 | (timefns-tests--decode-time look "IST-5:30" |
| 85 | '(59 29 5 1 7 1972 6 nil 19800))) | 87 | (list sec 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))))))) | ||
| 88 | 88 | ||
| 89 | (ert-deftest decode-then-encode-time () | 89 | (ert-deftest decode-then-encode-time () |
| 90 | (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 |