diff options
| author | Lars Ingebrigtsen | 2019-07-29 14:15:03 +0200 |
|---|---|---|
| committer | Lars Ingebrigtsen | 2019-07-29 14:22:38 +0200 |
| commit | 6cfda69d72cb9debefc48d0d95e341d389e7303a (patch) | |
| tree | 031f4d820ab5a0113f25a4d9096c0c5fde98499d | |
| parent | e4f957fb0794b5616deb0abf792e11132c06e3a9 (diff) | |
| download | emacs-6cfda69d72cb9debefc48d0d95e341d389e7303a.tar.gz emacs-6cfda69d72cb9debefc48d0d95e341d389e7303a.zip | |
Add support for dealing with decoded time structures
* doc/lispref/os.texi (Time Conversion): Document the new
functions that work on decoded time.
(Time Calculations): Document new date/time functions.
* lisp/simple.el (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): New accessor functions for decoded time values.
* lisp/calendar/time-date.el (date-days-in-month)
(date-ordinal-to-time): New functions.
(decoded-time--alter-month, decoded-time--alter-day)
(decoded-time--alter-second, make-decoded-time): New functions
added to manipulate decoded time structures.
* src/timefns.c (Fdecode_time): Mention the new accessors.
* test/lisp/calendar/time-date-tests.el: New file to test the
decoded time functions and the other new functions.
| -rw-r--r-- | doc/lispref/os.texi | 64 | ||||
| -rw-r--r-- | etc/NEWS | 15 | ||||
| -rw-r--r-- | lisp/calendar/time-date.el | 149 | ||||
| -rw-r--r-- | lisp/simple.el | 76 | ||||
| -rw-r--r-- | src/timefns.c | 6 | ||||
| -rw-r--r-- | test/lisp/calendar/time-date-tests.el | 109 |
6 files changed, 419 insertions, 0 deletions
diff --git a/doc/lispref/os.texi b/doc/lispref/os.texi index fef954eb7a3..d397a125738 100644 --- a/doc/lispref/os.texi +++ b/doc/lispref/os.texi | |||
| @@ -1466,6 +1466,60 @@ seconds east of Greenwich. | |||
| 1466 | 1466 | ||
| 1467 | @strong{Common Lisp Note:} Common Lisp has different meanings for | 1467 | @strong{Common Lisp Note:} Common Lisp has different meanings for |
| 1468 | @var{dow} and @var{utcoff}. | 1468 | @var{dow} and @var{utcoff}. |
| 1469 | |||
| 1470 | To access (or alter) the elements in the time value, the | ||
| 1471 | @code{decoded-time-second}, @code{decoded-time-minute}, | ||
| 1472 | @code{decoded-time-hour}, @code{decoded-time-day}, | ||
| 1473 | @code{decoded-time-month}, @code{decoded-time-year}, | ||
| 1474 | @code{decoded-time-weekday}, @code{decoded-time-dst} and | ||
| 1475 | @code{decoded-time-zone} accessors can be used. | ||
| 1476 | |||
| 1477 | For instance, to increase the year in a decoded time, you could say: | ||
| 1478 | |||
| 1479 | @lisp | ||
| 1480 | (setf (decoded-time-year decoded-time) | ||
| 1481 | (+ (decoded-time-year decoded-time) 4)) | ||
| 1482 | @end lisp | ||
| 1483 | |||
| 1484 | Also see the following function. | ||
| 1485 | |||
| 1486 | @end defun | ||
| 1487 | |||
| 1488 | @defun decoded-time-add time delta | ||
| 1489 | This function takes a decoded time structure and adds @var{delta} | ||
| 1490 | (also a decoded time structure) to it. Elements in @var{delta} that | ||
| 1491 | are @code{nil} are ignored. | ||
| 1492 | |||
| 1493 | For instance, if you want ``same time next month'', you | ||
| 1494 | could say: | ||
| 1495 | |||
| 1496 | @lisp | ||
| 1497 | (let ((time (decode-time)) | ||
| 1498 | (delta (make-decoded-time :month 2))) | ||
| 1499 | (encode-time (decoded-time-add time delta))) | ||
| 1500 | @end lisp | ||
| 1501 | |||
| 1502 | If this date doesn't exist (if you're running this on January 31st, | ||
| 1503 | for instance), then the date will be shifted back until you get a | ||
| 1504 | valid date (which will be February 28th or 29th, depending). | ||
| 1505 | |||
| 1506 | Fields are added in a most to least significant order, so if the | ||
| 1507 | adjustment described above happens, it happens before adding days, | ||
| 1508 | hours, minutes or seconds. | ||
| 1509 | |||
| 1510 | The values in @var{delta} can be negative to subtract values instead. | ||
| 1511 | |||
| 1512 | The return value is a decoded time structure. | ||
| 1513 | @end defun | ||
| 1514 | |||
| 1515 | @defun make-decoded-time &key second minute hour day month year dst zone | ||
| 1516 | Return a decoded time structure with only the given keywords filled | ||
| 1517 | out, leaving the rest @code{nil}. For instance, to get a structure | ||
| 1518 | that represents ``two months'', you could say: | ||
| 1519 | |||
| 1520 | @lisp | ||
| 1521 | (make-decoded-time :month 2) | ||
| 1522 | @end lisp | ||
| 1469 | @end defun | 1523 | @end defun |
| 1470 | 1524 | ||
| 1471 | @defun encode-time &optional time form &rest obsolescent-arguments | 1525 | @defun encode-time &optional time form &rest obsolescent-arguments |
| @@ -1867,6 +1921,16 @@ This returns the day number within the year corresponding to @var{time-value}. | |||
| 1867 | This function returns @code{t} if @var{year} is a leap year. | 1921 | This function returns @code{t} if @var{year} is a leap year. |
| 1868 | @end defun | 1922 | @end defun |
| 1869 | 1923 | ||
| 1924 | @defun date-days-in-month year month | ||
| 1925 | Return the number of days in @var{month} in @var{year}. For instance, | ||
| 1926 | there's 29 days in February 2004. | ||
| 1927 | @end defun | ||
| 1928 | |||
| 1929 | @defun date-ordinal-to-time year ordinal | ||
| 1930 | Return the date of @var{ordinal} in @var{year} as a decoded time | ||
| 1931 | structure. For instance, the 120th day in 2004 is April 29th. | ||
| 1932 | @end defun | ||
| 1933 | |||
| 1870 | @node Timers | 1934 | @node Timers |
| 1871 | @section Timers for Delayed Execution | 1935 | @section Timers for Delayed Execution |
| 1872 | @cindex timers | 1936 | @cindex timers |
| @@ -2069,6 +2069,21 @@ that acts like the '0' flag but also puts a '+' before nonnegative | |||
| 2069 | years containing more than four digits. This is for compatibility | 2069 | years containing more than four digits. This is for compatibility |
| 2070 | with POSIX.1-2017. | 2070 | with POSIX.1-2017. |
| 2071 | 2071 | ||
| 2072 | +++ | ||
| 2073 | *** To access (or alter) the elements a decoded time value, the | ||
| 2074 | 'decoded-time-second', 'decoded-time-minute', 'decoded-time-hour', | ||
| 2075 | 'decoded-time-day', 'decoded-time-month', 'decoded-time-year', | ||
| 2076 | 'decoded-time-weekday', 'decoded-time-dst' and 'decoded-time-zone' | ||
| 2077 | accessors can be used. | ||
| 2078 | |||
| 2079 | +++ | ||
| 2080 | *** The new functions `date-days-in-month' (which will say how many | ||
| 2081 | days there are in a month in a specific year), `date-ordinal-to-time' | ||
| 2082 | (that computes the date of an ordinal day), `decoded-time-add' for | ||
| 2083 | doing computations on a decoded time structure), and | ||
| 2084 | `make-decoded-time' (for making a decoded time structure with only the | ||
| 2085 | given keywords filled out) have been added. | ||
| 2086 | |||
| 2072 | ** 'define-minor-mode' automatically documents the meaning of ARG. | 2087 | ** 'define-minor-mode' automatically documents the meaning of ARG. |
| 2073 | 2088 | ||
| 2074 | +++ | 2089 | +++ |
diff --git a/lisp/calendar/time-date.el b/lisp/calendar/time-date.el index 2c0280ccf3b..d299dc5e7d1 100644 --- a/lisp/calendar/time-date.el +++ b/lisp/calendar/time-date.el | |||
| @@ -36,6 +36,9 @@ | |||
| 36 | 36 | ||
| 37 | ;;; Code: | 37 | ;;; Code: |
| 38 | 38 | ||
| 39 | (require 'cl-lib) | ||
| 40 | (require 'subr-x) | ||
| 41 | |||
| 39 | (defmacro with-decoded-time-value (varlist &rest body) | 42 | (defmacro with-decoded-time-value (varlist &rest body) |
| 40 | "Decode a time value and bind it according to VARLIST, then eval BODY. | 43 | "Decode a time value and bind it according to VARLIST, then eval BODY. |
| 41 | 44 | ||
| @@ -349,6 +352,152 @@ is output until the first non-zero unit is encountered." | |||
| 349 | (<= (car here) delay))) | 352 | (<= (car here) delay))) |
| 350 | (concat (format "%.2f" (/ delay (car (cddr here)))) (cadr here)))))) | 353 | (concat (format "%.2f" (/ delay (car (cddr here)))) (cadr here)))))) |
| 351 | 354 | ||
| 355 | (defun date-days-in-month (year month) | ||
| 356 | "The number of days in MONTH in YEAR." | ||
| 357 | (if (= month 2) | ||
| 358 | (if (date-leap-year-p year) | ||
| 359 | 29 | ||
| 360 | 28) | ||
| 361 | (if (memq month '(1 3 5 7 8 10 12)) | ||
| 362 | 31 | ||
| 363 | 30))) | ||
| 364 | |||
| 365 | (defun date-ordinal-to-time (year ordinal) | ||
| 366 | "Convert a YEAR/ORDINAL to the equivalent `decoded-time' structure. | ||
| 367 | ORDINAL is the number of days since the start of the year, with | ||
| 368 | January 1st being 1." | ||
| 369 | (let ((month 1)) | ||
| 370 | (while (> ordinal (date-days-in-month year month)) | ||
| 371 | (setq ordinal (- ordinal (date-days-in-month year month)) | ||
| 372 | month (1+ month))) | ||
| 373 | (list nil nil nil ordinal month year nil nil nil))) | ||
| 374 | |||
| 375 | (defun decoded-time-add (time delta) | ||
| 376 | "Add DELTA to TIME, both of which are `decoded-time' structures. | ||
| 377 | TIME should represent a time, while DELTA should only have | ||
| 378 | non-nil integers for the values that should be altered. | ||
| 379 | |||
| 380 | For instance, if you want to \"add two months\" to TIME, then | ||
| 381 | leave all other fields but the month field in DELTA nil, and make | ||
| 382 | the month field 2. The values in DELTA can be negative. | ||
| 383 | |||
| 384 | If applying a month/year delta leaves the time spec invalid, it | ||
| 385 | is decreased to be valid (\"add one month\" to January 31st 2019 | ||
| 386 | will yield a result of February 28th 2019 and \"add one year\" to | ||
| 387 | February 29th 2020 will result in February 28th 2021). | ||
| 388 | |||
| 389 | Fields are added in a most to least significant order, so if the | ||
| 390 | adjustment described above happens, it happens before adding | ||
| 391 | days, hours, minutes or seconds. | ||
| 392 | |||
| 393 | When changing the time bits in TIME (i.e., second/minute/hour), | ||
| 394 | changes in daylight saving time are not taken into account." | ||
| 395 | (let ((time (copy-sequence time)) | ||
| 396 | seconds) | ||
| 397 | ;; Years are simple. | ||
| 398 | (when (decoded-time-year delta) | ||
| 399 | (cl-incf (decoded-time-year time) (decoded-time-year delta))) | ||
| 400 | |||
| 401 | ;; Months are pretty simple. | ||
| 402 | (when (decoded-time-month delta) | ||
| 403 | (let ((new (+ (decoded-time-month time) (decoded-time-month delta)))) | ||
| 404 | (setf (decoded-time-month time) (mod new 12)) | ||
| 405 | (cl-incf (decoded-time-year time) (/ new 12)))) | ||
| 406 | |||
| 407 | ;; Adjust for month length (as described in the doc string). | ||
| 408 | (setf (decoded-time-day time) | ||
| 409 | (min (date-days-in-month (decoded-time-year time) | ||
| 410 | (decoded-time-month time)) | ||
| 411 | (decoded-time-day time))) | ||
| 412 | |||
| 413 | ;; Days are iterative. | ||
| 414 | (when-let* ((days (decoded-time-day delta))) | ||
| 415 | (let ((increase (> days 0)) | ||
| 416 | (days (abs days))) | ||
| 417 | (while (> days 0) | ||
| 418 | (decoded-time--alter-day time increase) | ||
| 419 | (cl-decf days)))) | ||
| 420 | |||
| 421 | ;; Do the time part, which is pretty simple (except for leap | ||
| 422 | ;; seconds, I guess). | ||
| 423 | (setq seconds (+ (* (or (decoded-time-hour delta) 0) 3600) | ||
| 424 | (* (or (decoded-time-minute delta) 0) 60) | ||
| 425 | (or (decoded-time-second delta) 0))) | ||
| 426 | |||
| 427 | ;; Time zone adjustments are basically the same as time adjustments. | ||
| 428 | (setq seconds (+ seconds (or (decoded-time-zone delta) 0))) | ||
| 429 | |||
| 430 | (cond | ||
| 431 | ((> seconds 0) | ||
| 432 | (decoded-time--alter-second time seconds t)) | ||
| 433 | ((< seconds 0) | ||
| 434 | (decoded-time--alter-second time (abs seconds) nil))) | ||
| 435 | |||
| 436 | time)) | ||
| 437 | |||
| 438 | (defun decoded-time--alter-month (time increase) | ||
| 439 | "Increase or decrease the month in TIME by 1." | ||
| 440 | (if increase | ||
| 441 | (progn | ||
| 442 | (cl-incf (decoded-time-month time)) | ||
| 443 | (when (> (decoded-time-month time) 12) | ||
| 444 | (setf (decoded-time-month time) 1) | ||
| 445 | (cl-incf (decoded-time-year time)))) | ||
| 446 | (cl-decf (decoded-time-month time)) | ||
| 447 | (when (zerop (decoded-time-month time)) | ||
| 448 | (setf (decoded-time-month time) 12) | ||
| 449 | (cl-decf (decoded-time-year time))))) | ||
| 450 | |||
| 451 | (defun decoded-time--alter-day (time increase) | ||
| 452 | "Increase or decrease the day in TIME by 1." | ||
| 453 | (if increase | ||
| 454 | (progn | ||
| 455 | (cl-incf (decoded-time-day time)) | ||
| 456 | (when (> (decoded-time-day time) | ||
| 457 | (date-days-in-month (decoded-time-year time) | ||
| 458 | (decoded-time-month time))) | ||
| 459 | (setf (decoded-time-day time) 1) | ||
| 460 | (decoded-time--alter-month time t))) | ||
| 461 | (cl-decf (decoded-time-day time)) | ||
| 462 | (when (zerop (decoded-time-day time)) | ||
| 463 | (decoded-time--alter-month time nil) | ||
| 464 | (setf (decoded-time-day time) | ||
| 465 | (date-days-in-month (decoded-time-year time) | ||
| 466 | (decoded-time-month time)))))) | ||
| 467 | |||
| 468 | (defun decoded-time--alter-second (time seconds increase) | ||
| 469 | "Increase or decrease the time in TIME by SECONDS." | ||
| 470 | (let ((old (+ (* (or (decoded-time-hour time) 0) 3600) | ||
| 471 | (* (or (decoded-time-minute time) 0) 60) | ||
| 472 | (or (decoded-time-second time) 0)))) | ||
| 473 | |||
| 474 | (if increase | ||
| 475 | (progn | ||
| 476 | (setq old (+ old seconds)) | ||
| 477 | (setf (decoded-time-second time) (% old 60) | ||
| 478 | (decoded-time-minute time) (% (/ old 60) 60) | ||
| 479 | (decoded-time-hour time) (% (/ old 3600) 24)) | ||
| 480 | ;; Hm... DST... | ||
| 481 | (let ((days (/ old (* 60 60 24)))) | ||
| 482 | (while (> days 0) | ||
| 483 | (decoded-time--alter-day time t) | ||
| 484 | (cl-decf days)))) | ||
| 485 | (setq old (abs (- old seconds))) | ||
| 486 | (setf (decoded-time-second time) (% old 60) | ||
| 487 | (decoded-time-minute time) (% (/ old 60) 60) | ||
| 488 | (decoded-time-hour time) (% (/ old 3600) 24)) | ||
| 489 | ;; Hm... DST... | ||
| 490 | (let ((days (/ old (* 60 60 24)))) | ||
| 491 | (while (> days 0) | ||
| 492 | (decoded-time--alter-day time nil) | ||
| 493 | (cl-decf days)))))) | ||
| 494 | |||
| 495 | (cl-defun make-decoded-time (&key second minute hour | ||
| 496 | day month year | ||
| 497 | dst zone) | ||
| 498 | "Return a `decoded-time' structure with only the keywords given filled out." | ||
| 499 | (list second minute hour day month year nil dst zone)) | ||
| 500 | |||
| 352 | (provide 'time-date) | 501 | (provide 'time-date) |
| 353 | 502 | ||
| 354 | ;;; time-date.el ends here | 503 | ;;; time-date.el ends here |
diff --git a/lisp/simple.el b/lisp/simple.el index 75be4fe7cb5..8855045123f 100644 --- a/lisp/simple.el +++ b/lisp/simple.el | |||
| @@ -9063,6 +9063,82 @@ to capitalize ARG words." | |||
| 9063 | (capitalize-region (region-beginning) (region-end)) | 9063 | (capitalize-region (region-beginning) (region-end)) |
| 9064 | (capitalize-word arg))) | 9064 | (capitalize-word arg))) |
| 9065 | 9065 | ||
| 9066 | ;;; Accessors for `decode-time' values. | ||
| 9067 | |||
| 9068 | (defsubst decoded-time-second (time) | ||
| 9069 | "The seconds in TIME, which is a value returned by `decode-time'. | ||
| 9070 | This is an integer between 0 and 60 (inclusive). (60 is a leap | ||
| 9071 | second, which only some operating systems support.)" | ||
| 9072 | (nth 0 time)) | ||
| 9073 | |||
| 9074 | (defsubst decoded-time-minute (time) | ||
| 9075 | "The minutes in TIME, which is a value returned by `decode-time'. | ||
| 9076 | This is an integer between 0 and 59 (inclusive)." | ||
| 9077 | (nth 1 time)) | ||
| 9078 | |||
| 9079 | (defsubst decoded-time-hour (time) | ||
| 9080 | "The hours in TIME, which is a value returned by `decode-time'. | ||
| 9081 | This is an integer between 0 and 23 (inclusive)." | ||
| 9082 | (nth 2 time)) | ||
| 9083 | |||
| 9084 | (defsubst decoded-time-day (time) | ||
| 9085 | "The day-of-the-month in TIME, which is a value returned by `decode-time'. | ||
| 9086 | This is an integer between 1 and 31 (inclusive)." | ||
| 9087 | (nth 3 time)) | ||
| 9088 | |||
| 9089 | (defsubst decoded-time-month (time) | ||
| 9090 | "The month in TIME, which is a value returned by `decode-time'. | ||
| 9091 | This is an integer between 1 and 12 (inclusive). January is 1." | ||
| 9092 | (nth 4 time)) | ||
| 9093 | |||
| 9094 | (defsubst decoded-time-year (time) | ||
| 9095 | "The year in TIME, which is a value returned by `decode-time'. | ||
| 9096 | This is a four digit integer." | ||
| 9097 | (nth 5 time)) | ||
| 9098 | |||
| 9099 | (defsubst decoded-time-weekday (time) | ||
| 9100 | "The day-of-the-week in TIME, which is a value returned by `decode-time'. | ||
| 9101 | This is a number between 0 and 6, and 0 is Sunday." | ||
| 9102 | (nth 6 time)) | ||
| 9103 | |||
| 9104 | (defsubst decoded-time-dst (time) | ||
| 9105 | "The daylight saving time in TIME, which is a value returned by `decode-time'. | ||
| 9106 | This is t if daylight saving time is in effect, and nil if not." | ||
| 9107 | (nth 7 time)) | ||
| 9108 | |||
| 9109 | (defsubst decoded-time-zone (time) | ||
| 9110 | "The time zone in TIME, which is a value returned by `decode-time'. | ||
| 9111 | This is an integer indicating the UTC offset in seconds, i.e., | ||
| 9112 | the number of seconds east of Greenwich." | ||
| 9113 | (nth 8 time)) | ||
| 9114 | |||
| 9115 | (gv-define-setter decoded-time-second (second time) | ||
| 9116 | `(setf (nth 0 ,time) ,second)) | ||
| 9117 | |||
| 9118 | (gv-define-setter decoded-time-minute (minute time) | ||
| 9119 | `(setf (nth 1 ,time) ,minute)) | ||
| 9120 | |||
| 9121 | (gv-define-setter decoded-time-hour (hour time) | ||
| 9122 | `(setf (nth 2 ,time) ,hour)) | ||
| 9123 | |||
| 9124 | (gv-define-setter decoded-time-day (day time) | ||
| 9125 | `(setf (nth 3 ,time) ,day)) | ||
| 9126 | |||
| 9127 | (gv-define-setter decoded-time-month (month time) | ||
| 9128 | `(setf (nth 4 ,time) ,month)) | ||
| 9129 | |||
| 9130 | (gv-define-setter decoded-time-year (year time) | ||
| 9131 | `(setf (nth 5 ,time) ,year)) | ||
| 9132 | |||
| 9133 | ;; No setter for weekday, which is the 6th element. | ||
| 9134 | |||
| 9135 | (gv-define-setter decoded-time-dst (dst time) | ||
| 9136 | `(setf (nth 7 ,time) ,dst)) | ||
| 9137 | |||
| 9138 | (gv-define-setter decoded-time-zone (zone time) | ||
| 9139 | `(setf (nth 8 ,time) ,zone)) | ||
| 9140 | |||
| 9141 | |||
| 9066 | 9142 | ||
| 9067 | 9143 | ||
| 9068 | (provide 'simple) | 9144 | (provide 'simple) |
diff --git a/src/timefns.c b/src/timefns.c index 3b7ed460222..cce9dd51ba9 100644 --- a/src/timefns.c +++ b/src/timefns.c | |||
| @@ -1326,6 +1326,12 @@ the TZ environment variable. It can also be a list (as from | |||
| 1326 | `current-time-zone') or an integer (the UTC offset in seconds) applied | 1326 | `current-time-zone') or an integer (the UTC offset in seconds) applied |
| 1327 | without consideration for daylight saving time. | 1327 | without consideration for daylight saving time. |
| 1328 | 1328 | ||
| 1329 | To access (or alter) the elements in the time value, the | ||
| 1330 | `decoded-time-second', `decoded-time-minute', `decoded-time-hour', | ||
| 1331 | `decoded-time-day', `decoded-time-month', `decoded-time-year', | ||
| 1332 | `decoded-time-weekday', `decoded-time-dst' and `decoded-time-zone' | ||
| 1333 | accessors can be used. | ||
| 1334 | |||
| 1329 | The list has the following nine members: SEC is an integer between 0 | 1335 | The list has the following nine members: SEC is an integer between 0 |
| 1330 | and 60; SEC is 60 for a leap second, which only some operating systems | 1336 | and 60; SEC is 60 for a leap second, which only some operating systems |
| 1331 | support. MINUTE is an integer between 0 and 59. HOUR is an integer | 1337 | support. MINUTE is an integer between 0 and 59. HOUR is an integer |
diff --git a/test/lisp/calendar/time-date-tests.el b/test/lisp/calendar/time-date-tests.el new file mode 100644 index 00000000000..d6cf742bc53 --- /dev/null +++ b/test/lisp/calendar/time-date-tests.el | |||
| @@ -0,0 +1,109 @@ | |||
| 1 | ;;; time-date-tests.el --- tests for calendar/time-date.el -*- lexical-binding:t -*- | ||
| 2 | |||
| 3 | ;; Copyright (C) 2019 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | ;; This file is part of GNU Emacs. | ||
| 6 | |||
| 7 | ;; GNU Emacs is free software: you can redistribute it and/or modify | ||
| 8 | ;; it under the terms of the GNU General Public License as published by | ||
| 9 | ;; the Free Software Foundation, either version 3 of the License, or | ||
| 10 | ;; (at your option) any later version. | ||
| 11 | |||
| 12 | ;; GNU Emacs is distributed in the hope that it will be useful, | ||
| 13 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | ;; GNU General Public License for more details. | ||
| 16 | |||
| 17 | ;; You should have received a copy of the GNU General Public License | ||
| 18 | ;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. | ||
| 19 | |||
| 20 | ;;; Code: | ||
| 21 | |||
| 22 | (require 'ert) | ||
| 23 | (require 'time-date) | ||
| 24 | |||
| 25 | (ert-deftest test-leap-year () | ||
| 26 | (should-not (date-leap-year-p 1999)) | ||
| 27 | (should-not (date-leap-year-p 1900)) | ||
| 28 | (should (date-leap-year-p 2000)) | ||
| 29 | (should (date-leap-year-p 2004))) | ||
| 30 | |||
| 31 | (ert-deftest test-days-in-month () | ||
| 32 | (should (= (date-days-in-month 2004 2) 29)) | ||
| 33 | (should (= (date-days-in-month 2004 3) 31)) | ||
| 34 | (should-not (= (date-days-in-month 1900 3) 28))) | ||
| 35 | |||
| 36 | (ert-deftest test-ordinal () | ||
| 37 | (should (equal (date-ordinal-to-time 2008 271) | ||
| 38 | '(0 0 0 27 9 2008 nil nil nil))) | ||
| 39 | (should (equal (date-ordinal-to-time 2008 1) | ||
| 40 | '(0 0 0 1 1 2008 nil nil nil))) | ||
| 41 | (should (equal (date-ordinal-to-time 2008 32) | ||
| 42 | '(0 0 0 1 2 2008 nil nil nil))) | ||
| 43 | (should (equal (date-ordinal-to-time 1981 095) | ||
| 44 | '(0 0 0 5 4 1981 nil nil nil)))) | ||
| 45 | |||
| 46 | (cl-defmethod mdec (&key second minute hour | ||
| 47 | day month year | ||
| 48 | dst zone) | ||
| 49 | (list second minute hour day month year nil dst zone)) | ||
| 50 | |||
| 51 | (ert-deftest test-decoded-add () | ||
| 52 | (let ((time '(12 15 16 8 7 2019 1 t 7200))) | ||
| 53 | (should (equal (decoded-time-add time (mdec :year 1)) | ||
| 54 | '(12 15 16 8 7 2020 1 t 7200))) | ||
| 55 | |||
| 56 | (should (equal (decoded-time-add time (mdec :year -2)) | ||
| 57 | '(12 15 16 8 7 2017 1 t 7200))) | ||
| 58 | |||
| 59 | (should (equal (decoded-time-add time (mdec :month 1)) | ||
| 60 | '(12 15 16 8 8 2019 1 t 7200))) | ||
| 61 | |||
| 62 | (should (equal (decoded-time-add time (mdec :month 10)) | ||
| 63 | '(12 15 16 8 5 2020 1 t 7200))) | ||
| 64 | |||
| 65 | (should (equal (decoded-time-add time (mdec :day 1)) | ||
| 66 | '(12 15 16 9 7 2019 1 t 7200))) | ||
| 67 | |||
| 68 | (should (equal (decoded-time-add time (mdec :day -1)) | ||
| 69 | '(12 15 16 7 7 2019 1 t 7200))) | ||
| 70 | |||
| 71 | (should (equal (decoded-time-add time (mdec :day 30)) | ||
| 72 | '(12 15 16 7 8 2019 1 t 7200))) | ||
| 73 | |||
| 74 | (should (equal (decoded-time-add time (mdec :day -365)) | ||
| 75 | '(12 15 16 8 7 2018 1 t 7200))) | ||
| 76 | |||
| 77 | (should (equal (decoded-time-add time (mdec :day 365)) | ||
| 78 | '(12 15 16 7 7 2020 1 t 7200))) | ||
| 79 | |||
| 80 | ;; 2020 is a leap year. | ||
| 81 | (should (equal (decoded-time-add time (mdec :day 366)) | ||
| 82 | '(12 15 16 8 7 2020 1 t 7200))) | ||
| 83 | |||
| 84 | (should (equal (decoded-time-add time (mdec :second 1)) | ||
| 85 | '(13 15 16 8 7 2019 1 t 7200))) | ||
| 86 | |||
| 87 | (should (equal (decoded-time-add time (mdec :second -1)) | ||
| 88 | '(11 15 16 8 7 2019 1 t 7200))) | ||
| 89 | |||
| 90 | (should (equal (decoded-time-add time (mdec :second 61)) | ||
| 91 | '(13 16 16 8 7 2019 1 t 7200))) | ||
| 92 | |||
| 93 | (should (equal (decoded-time-add time (mdec :hour 1 :minute 2 :second 3)) | ||
| 94 | '(15 17 17 8 7 2019 1 t 7200))) | ||
| 95 | |||
| 96 | (should (equal (decoded-time-add time (mdec :hour 24)) | ||
| 97 | '(12 15 16 9 7 2019 1 t 7200))) | ||
| 98 | )) | ||
| 99 | |||
| 100 | (ert-deftest test-decoded-add-zone () | ||
| 101 | (let ((time '(12 15 16 8 7 2019 1 t 7200))) | ||
| 102 | (should (equal (decoded-time-add time (mdec :zone -3600)) | ||
| 103 | '(12 15 15 8 7 2019 1 t 7200))) | ||
| 104 | (should (equal (decoded-time-add time (mdec :zone -7200)) | ||
| 105 | '(12 15 14 8 7 2019 1 t 7200))))) | ||
| 106 | |||
| 107 | (require 'ert) | ||
| 108 | |||
| 109 | ;;; time-date-tests.el ends here | ||