aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Gildea2024-12-10 09:09:39 -0800
committerStephen Gildea2024-12-10 09:11:55 -0800
commit7665ec8df8d1c01211db6a85dda4813d6912ffee (patch)
tree6a863bf1f9973c6c211f26d2e7be314a623543d3
parentebd8feef1491907ebf4648a3aa38ddaa7fbf1dd2 (diff)
downloademacs-7665ec8df8d1c01211db6a85dda4813d6912ffee.tar.gz
emacs-7665ec8df8d1c01211db6a85dda4813d6912ffee.zip
time-stamp: properly abbreviate instead of truncating names
* lisp/time-stamp (time-stamp-string-preprocess): Stop truncating month and weekday name strings; it didn't internationalize well. Some historical conversions, previously accepted quietly, now warn. (time-stamp-format): Recommend the simpler formats implemented in 2019. * test/lisp/time-stamp-tests.el: Update tests and comments to match. Revert commit 83e4559664 (2022-07-01), which was working around the former confusion between truncation and abbreviation.
-rw-r--r--lisp/time-stamp.el166
-rw-r--r--test/lisp/time-stamp-tests.el273
2 files changed, 256 insertions, 183 deletions
diff --git a/lisp/time-stamp.el b/lisp/time-stamp.el
index a02c1d4532d..50d75ecac01 100644
--- a/lisp/time-stamp.el
+++ b/lisp/time-stamp.el
@@ -41,53 +41,59 @@
41 :group 'extensions) 41 :group 'extensions)
42 42
43 43
44(defcustom time-stamp-format "%Y-%02m-%02d %02H:%02M:%02S %l" 44(defcustom time-stamp-format "%Y-%m-%d %H:%M:%S %l"
45 "Format of the string inserted by \\[time-stamp]. 45 "Format of the string inserted by \\[time-stamp].
46This is a string, used verbatim except for character sequences beginning 46The string is inserted verbatim except for character sequences beginning
47with %, as follows. 47with %, which are converted as follows:
48 48
49%:A weekday name: `Monday' %#A gives uppercase: `MONDAY' 49%A weekday name: `Monday' %a abbreviated weekday name: `Mon'
50%3a abbreviated weekday: `Mon' %#a gives uppercase: `MON' 50%B month name: `January' %b abbreviated month name: `Jan'
51%:B month name: `January' %#B gives uppercase: `JANUARY' 51%d day of month
52%3b abbreviated month: `Jan' %#b gives uppercase: `JAN' 52%H 24-hour clock hour %I 12-hour clock hour
53%02d day of month 53%m month number
54%02H 24-hour clock hour 54%M minute
55%02I 12-hour clock hour 55%p `AM' or `PM'
56%02m month number 56%S seconds
57%02M minute
58%#p `am' or `pm' %P gives uppercase: `AM' or `PM'
59%02S seconds
60%w day number of week, Sunday is 0 57%w day number of week, Sunday is 0
61%02y 2-digit year %Y 4-digit year 58%Y 4-digit year %y 2-digit year
62%Z time zone name: `EST' %#Z gives lowercase: `est' 59%Z time zone name: `EST'
63%5z time zone offset: `-0500' (since Emacs 27; see note below) 60%-z zone offset with hour: `-08' %:::z adds colons as needed: `+05:30'
61%5z zone offset with mins: `-0800' %:z adds colon: `-08:00'
64 62
65Non-date items: 63Non-date items:
66%% a literal percent character: `%' 64%% literal percent character: \"%\"
67%f file name without directory %F absolute file name 65%f file name without directory %F absolute file name
68%l login name %L full name of logged-in user 66%l login name %L full name of logged-in user
69%q unqualified host name %Q fully-qualified host name 67%q unqualified host name %Q fully-qualified host name
70%h mail host name 68%h mail host name
71 69
72Decimal digits between the % and the type character specify the 70A \"#\" after the % changes the case of letters. For example, on Mondays,
73field width. Strings are truncated on the right. 71in the default locale, \"%#A\" converts to \"MONDAY\".
74A leading zero in the field width zero-fills a number.
75 72
76For example, to get a common format used by the `date' command, 73Decimal digits before the type character specify the minimum field
77use \"%3a %3b %2d %02H:%02M:%02S %Z %Y\". 74width. A \"0\" before the field width adds insignificant zeroes
75as appropriate, otherwise the padding is done with spaces.
76
77If no padding is specified, a field that can be one or two digits is padded
78with \"0\" to two digits if necessary. Follow the % with \"_\" to pad with a
79space instead, or follow it with \"-\" to suppress this padding entirely.
80Thus, on the 5th of the month, the day is converted as follows:
81
82\"%d\" -> \"05\"
83\"%_d\" -> \" 5\"
84\"%-d\" -> \"5\"
85
86For example, to get a common format used by the \"date\" command,
87use \"%a %b %_d %H:%M:%S %Z %Y\".
78 88
79The values of non-numeric formatted items depend on the locale 89The values of non-numeric formatted items depend on the locale
80setting recorded in `system-time-locale' and `locale-coding-system'. 90setting recorded in `system-time-locale' and `locale-coding-system'.
81The examples here are for the default (`C') locale. 91The examples here are for the default (\"C\") locale.
82`time-stamp-time-zone' controls the time zone used. 92`time-stamp-time-zone' controls the time zone used.
83 93
84The default padding of some formats has changed to be more compatible 94Some of the conversions recommended here work only in Emacs 27 or later.
85with format-time-string. To be compatible with older versions of Emacs, 95If your files might be edited by older versions of Emacs also, you should
86specify a padding width (as shown) or use the : modifier to request the 96limit yourself to the formats recommended by that older version."
87transitional behavior (again, as shown).
88
89The behavior of `%5z' is new in Emacs 27. If your files might be
90edited by older versions of Emacs also, do not use this format yet."
91 :type 'string 97 :type 'string
92 :version "27.1") 98 :version "27.1")
93;;;###autoload(put 'time-stamp-format 'safe-local-variable 'stringp) 99;;;###autoload(put 'time-stamp-format 'safe-local-variable 'stringp)
@@ -273,11 +279,11 @@ Examples:
273// time-stamp-pattern: \"-9/^Last modified: %%$\" 279// time-stamp-pattern: \"-9/^Last modified: %%$\"
274 (sets `time-stamp-line-limit', `time-stamp-start' and `time-stamp-end') 280 (sets `time-stamp-line-limit', `time-stamp-start' and `time-stamp-end')
275 281
276@c time-stamp-pattern: \"@set Time-stamp: %:B %1d, %Y$\" 282@c time-stamp-pattern: \"@set Time-stamp: %B %-d, %Y$\"
277 (sets `time-stamp-start', `time-stamp-format' and `time-stamp-end') 283 (sets `time-stamp-start', `time-stamp-format' and `time-stamp-end')
278 284
279%% time-stamp-pattern: \"newcommand{\\\\\\\\timestamp}{%%}\" 285%% time-stamp-pattern: \"newcommand{\\\\\\\\timestamp}{%%}\"
280 (sets `time-stamp-start'and `time-stamp-end') 286 (sets `time-stamp-start' and `time-stamp-end')
281 287
282 288
283See also `time-stamp-count' and `time-stamp-inserts-lines'.") 289See also `time-stamp-count' and `time-stamp-inserts-lines'.")
@@ -483,7 +489,7 @@ normally the current time is used."
483;;; At all times, all the formats recommended in the doc string 489;;; At all times, all the formats recommended in the doc string
484;;; of time-stamp-format will work not only in the current version of 490;;; of time-stamp-format will work not only in the current version of
485;;; Emacs, but in all versions that have been released within the past 491;;; Emacs, but in all versions that have been released within the past
486;;; two years. 492;;; five years.
487;;; The : modifier is a temporary conversion feature used to resolve 493;;; The : modifier is a temporary conversion feature used to resolve
488;;; ambiguous formats--formats that are changing (over time) incompatibly. 494;;; ambiguous formats--formats that are changing (over time) incompatibly.
489(defun time-stamp-string-preprocess (format &optional time) 495(defun time-stamp-string-preprocess (format &optional time)
@@ -576,10 +582,22 @@ and all `time-stamp-format' compatibility."
576 (time-stamp--format "%#a" time) 582 (time-stamp--format "%#a" time)
577 (time-stamp--format "%a" time)))) 583 (time-stamp--format "%a" time))))
578 ((eq cur-char ?A) 584 ((eq cur-char ?A)
579 (if (or change-case upcase (not (string-equal field-width 585 (if (and (>= (string-to-number field-width) 1)
580 ""))) 586 (<= (string-to-number field-width) 3)
581 (time-stamp--format "%#A" time) 587 (not flag-minimize)
582 (time-stamp--format "%A" time))) 588 (not flag-pad-with-spaces))
589 (progn
590 (time-stamp-conv-warn "%3A" "%#a")
591 (time-stamp--format "%#a" time))
592 (if (or change-case upcase)
593 (time-stamp--format "%#A" time)
594 (if (or (> alt-form 0)
595 flag-minimize flag-pad-with-spaces
596 (string-equal field-width ""))
597 (time-stamp--format "%A" time)
598 (time-stamp-conv-warn (format "%%%sA" field-width)
599 (format "%%#%sA" field-width))
600 (time-stamp--format "%#A" time)))))
583 ((eq cur-char ?b) ;month name 601 ((eq cur-char ?b) ;month name
584 (if (> alt-form 0) 602 (if (> alt-form 0)
585 (if (string-equal field-width "") 603 (if (string-equal field-width "")
@@ -589,10 +607,22 @@ and all `time-stamp-format' compatibility."
589 (time-stamp--format "%#b" time) 607 (time-stamp--format "%#b" time)
590 (time-stamp--format "%b" time)))) 608 (time-stamp--format "%b" time))))
591 ((eq cur-char ?B) 609 ((eq cur-char ?B)
592 (if (or change-case upcase (not (string-equal field-width 610 (if (and (>= (string-to-number field-width) 1)
593 ""))) 611 (<= (string-to-number field-width) 3)
594 (time-stamp--format "%#B" time) 612 (not flag-minimize)
595 (time-stamp--format "%B" time))) 613 (not flag-pad-with-spaces))
614 (progn
615 (time-stamp-conv-warn "%3B" "%#b")
616 (time-stamp--format "%#b" time))
617 (if (or change-case upcase)
618 (time-stamp--format "%#B" time)
619 (if (or (> alt-form 0)
620 flag-minimize flag-pad-with-spaces
621 (string-equal field-width ""))
622 (time-stamp--format "%B" time)
623 (time-stamp-conv-warn (format "%%%sB" field-width)
624 (format "%%#%sB" field-width))
625 (time-stamp--format "%#B" time)))))
596 ((eq cur-char ?d) ;day of month, 1-31 626 ((eq cur-char ?d) ;day of month, 1-31
597 (time-stamp-do-number cur-char alt-form field-width time)) 627 (time-stamp-do-number cur-char alt-form field-width time))
598 ((eq cur-char ?H) ;hour, 0-23 628 ((eq cur-char ?H) ;hour, 0-23
@@ -620,13 +650,15 @@ and all `time-stamp-format' compatibility."
620 ((eq cur-char ?w) ;weekday number, Sunday is 0 650 ((eq cur-char ?w) ;weekday number, Sunday is 0
621 (time-stamp--format "%w" time)) 651 (time-stamp--format "%w" time))
622 ((eq cur-char ?y) ;year 652 ((eq cur-char ?y) ;year
623 (if (> alt-form 0) 653 (if (= alt-form 0)
624 (string-to-number (time-stamp--format "%Y" time)) 654 (if (or (string-equal field-width "")
625 (if (or (string-equal field-width "") 655 (<= (string-to-number field-width) 2))
626 (<= (string-to-number field-width) 2)) 656 (string-to-number (time-stamp--format "%y" time))
627 (string-to-number (time-stamp--format "%y" time)) 657 (time-stamp-conv-warn
628 (time-stamp-conv-warn (format "%%%sy" field-width) "%Y") 658 (format "%%%sy" field-width) "%Y")
629 (string-to-number (time-stamp--format "%Y" time))))) 659 (string-to-number (time-stamp--format "%Y" time)))
660 (time-stamp-conv-warn "%:y" "%Y")
661 (string-to-number (time-stamp--format "%Y" time))))
630 ((eq cur-char ?Y) ;4-digit year 662 ((eq cur-char ?Y) ;4-digit year
631 (string-to-number (time-stamp--format "%Y" time))) 663 (string-to-number (time-stamp--format "%Y" time)))
632 ((eq cur-char ?z) ;time zone offset 664 ((eq cur-char ?z) ;time zone offset
@@ -673,10 +705,13 @@ and all `time-stamp-format' compatibility."
673 (or buffer-file-name 705 (or buffer-file-name
674 time-stamp-no-file)) 706 time-stamp-no-file))
675 ((eq cur-char ?s) ;system name, legacy 707 ((eq cur-char ?s) ;system name, legacy
708 (time-stamp-conv-warn "%s" "%Q")
676 (system-name)) 709 (system-name))
677 ((eq cur-char ?u) ;user name, legacy 710 ((eq cur-char ?u) ;user name, legacy
711 (time-stamp-conv-warn "%u" "%l")
678 (user-login-name)) 712 (user-login-name))
679 ((eq cur-char ?U) ;user full name, legacy 713 ((eq cur-char ?U) ;user full name, legacy
714 (time-stamp-conv-warn "%U" "%L")
680 (user-full-name)) 715 (user-full-name))
681 ((eq cur-char ?l) ;login name 716 ((eq cur-char ?l) ;login name
682 (user-login-name)) 717 (user-login-name))
@@ -694,25 +729,14 @@ and all `time-stamp-format' compatibility."
694 )) 729 ))
695 (and (numberp field-result) 730 (and (numberp field-result)
696 (= alt-form 0) 731 (= alt-form 0)
697 (string-equal field-width "") 732 (or (string-equal field-width "")
733 (string-equal field-width "0"))
698 ;; no width provided; set width for default 734 ;; no width provided; set width for default
699 (setq field-width "02")) 735 (setq field-width "02"))
700 (let ((padded-result 736 (format (format "%%%s%c"
701 (format (format "%%%s%c" 737 field-width
702 field-width 738 (if (numberp field-result) ?d ?s))
703 (if (numberp field-result) ?d ?s)) 739 (or field-result ""))))
704 (or field-result ""))))
705 (let* ((initial-length (length padded-result))
706 (desired-length (if (string-equal field-width "")
707 initial-length
708 (string-to-number field-width))))
709 (if (> initial-length desired-length)
710 ;; truncate strings on right
711 (if (and (stringp field-result)
712 (not (eq cur-char ?z))) ;offset does not truncate
713 (substring padded-result 0 desired-length)
714 padded-result) ;numbers don't truncate
715 padded-result)))))
716 (t 740 (t
717 (char-to-string cur-char))))) 741 (char-to-string cur-char)))))
718 (setq ind (1+ ind))) 742 (setq ind (1+ ind)))
@@ -883,7 +907,7 @@ OFFSET-SECS is the time zone offset (in seconds east of UTC) to be
883formatted according to the preceding parameters. 907formatted according to the preceding parameters.
884 908
885This is an internal function used by `time-stamp'." 909This is an internal function used by `time-stamp'."
886 ;; The caller of this function must have already parsed the %z 910 ;; Callers of this function need to have already parsed the %z
887 ;; format string; this function accepts just the parts of the format. 911 ;; format string; this function accepts just the parts of the format.
888 ;; `time-stamp-string-preprocess' is the full-fledged parser normally 912 ;; `time-stamp-string-preprocess' is the full-fledged parser normally
889 ;; used. The unit test (in time-stamp-tests.el) defines the simpler 913 ;; used. The unit test (in time-stamp-tests.el) defines the simpler
diff --git a/test/lisp/time-stamp-tests.el b/test/lisp/time-stamp-tests.el
index b05904ad017..7cf8f995c13 100644
--- a/test/lisp/time-stamp-tests.el
+++ b/test/lisp/time-stamp-tests.el
@@ -45,7 +45,7 @@
45 ,@body))) 45 ,@body)))
46 46
47(defmacro with-time-stamp-test-time (reference-time &rest body) 47(defmacro with-time-stamp-test-time (reference-time &rest body)
48 "Force any contained time-stamp call to use time REFERENCE-TIME." 48 "Force `time-stamp' to use time REFERENCE-TIME while evaluating BODY."
49 (declare (indent 1) (debug t)) 49 (declare (indent 1) (debug t))
50 `(cl-letf* 50 `(cl-letf*
51 ((orig-time-stamp-string-fn (symbol-function 'time-stamp-string)) 51 ((orig-time-stamp-string-fn (symbol-function 'time-stamp-string))
@@ -55,14 +55,14 @@
55 ,@body)) 55 ,@body))
56 56
57(defmacro with-time-stamp-system-name (name &rest body) 57(defmacro with-time-stamp-system-name (name &rest body)
58 "Force (system-name) to return NAME while evaluating BODY." 58 "Force `system-name' to return NAME while evaluating BODY."
59 (declare (indent 1) (debug t)) 59 (declare (indent 1) (debug t))
60 `(cl-letf (((symbol-function 'system-name) 60 `(cl-letf (((symbol-function 'system-name)
61 (lambda () ,name))) 61 (lambda () ,name)))
62 ,@body)) 62 ,@body))
63 63
64(defmacro time-stamp-should-warn (form) 64(defmacro time-stamp-should-warn (form)
65 "Similar to `should' but verifies that a format warning is generated." 65 "Similar to `should' and also verify that FORM generates a format warning."
66 (declare (debug t)) 66 (declare (debug t))
67 `(let ((warning-count 0)) 67 `(let ((warning-count 0))
68 (cl-letf (((symbol-function 'time-stamp-conv-warn) 68 (cl-letf (((symbol-function 'time-stamp-conv-warn)
@@ -269,70 +269,111 @@
269(ert-deftest time-stamp-format-day-of-week () 269(ert-deftest time-stamp-format-day-of-week ()
270 "Test time-stamp formats for named day of week." 270 "Test time-stamp formats for named day of week."
271 (with-time-stamp-test-env 271 (with-time-stamp-test-env
272 (let ((Mon (format-time-string "%a" ref-time1 t)) 272 (let* ((Mon (format-time-string "%a" ref-time1 t))
273 (MON (format-time-string "%^a" ref-time1 t)) 273 (MON (format-time-string "%^a" ref-time1 t))
274 (Monday (format-time-string "%A" ref-time1 t)) 274 (Monday (format-time-string "%A" ref-time1 t))
275 (MONDAY (format-time-string "%^A" ref-time1 t))) 275 (MONDAY (format-time-string "%^A" ref-time1 t))
276 ;; implemented and documented since 1997 276 (p4-Mon (string-pad Mon 4 ?\s t))
277 (should (equal (time-stamp-string "%3a" ref-time1) Mon)) 277 (p4-MON (string-pad MON 4 ?\s t))
278 (p10-Monday (string-pad Monday 10 ?\s t))
279 (p10-MONDAY (string-pad MONDAY 10 ?\s t)))
280 ;; implemented and recommended since 1997
278 (should (equal (time-stamp-string "%#A" ref-time1) MONDAY)) 281 (should (equal (time-stamp-string "%#A" ref-time1) MONDAY))
279 ;; documented 1997-2019 282 (should (equal (time-stamp-string "%#10A" ref-time1) p10-MONDAY))
280 (should (equal (time-stamp-string "%3A" ref-time1) 283 ;; implemented since 1997, recommended 1997-2024
281 (substring MONDAY 0 3))) 284 (should (equal (time-stamp-string "%3a" ref-time1) Mon))
285 ;; recommended 1997-2019
282 (should (equal (time-stamp-string "%:a" ref-time1) Monday)) 286 (should (equal (time-stamp-string "%:a" ref-time1) Monday))
283 ;; implemented since 2001, documented since 2019 287 ;; recommended 1997-2019, warned since 2024, will change
288 (time-stamp-should-warn
289 (should (equal (time-stamp-string "%3A" ref-time1) MON)))
290 (time-stamp-should-warn
291 (should (equal (time-stamp-string "%10A" ref-time1) p10-MONDAY)))
292 ;; implemented since 2001, recommended since 2019
284 (should (equal (time-stamp-string "%#a" ref-time1) MON)) 293 (should (equal (time-stamp-string "%#a" ref-time1) MON))
294 (should (equal (time-stamp-string "%#3a" ref-time1) MON))
295 (should (equal (time-stamp-string "%#4a" ref-time1) p4-MON))
296 ;; implemented since 2001, recommended 2019-2024
285 (should (equal (time-stamp-string "%:A" ref-time1) Monday)) 297 (should (equal (time-stamp-string "%:A" ref-time1) Monday))
286 ;; allowed but undocumented since 2019 (warned 1997-2019) 298 ;; broken 2019-2024
299 (should (equal (time-stamp-string "%:10A" ref-time1) p10-Monday))
300 ;; broken in 2019, changed in 2024
301 (should (equal (time-stamp-string "%-A" ref-time1) Monday))
302 (should (equal (time-stamp-string "%_A" ref-time1) Monday))
303 ;; allowed but not recommended since 2019 (warned 1997-2019)
287 (should (equal (time-stamp-string "%^A" ref-time1) MONDAY)) 304 (should (equal (time-stamp-string "%^A" ref-time1) MONDAY))
288 ;; warned 1997-2019, changed in 2019 305 ;; warned 1997-2019, changed in 2019, recommended (with caveat) since 2024
289 (should (equal (time-stamp-string "%a" ref-time1) Mon)) 306 (should (equal (time-stamp-string "%a" ref-time1) Mon))
307 (should (equal (time-stamp-string "%4a" ref-time1) p4-Mon))
308 (should (equal (time-stamp-string "%04a" ref-time1) p4-Mon))
309 (should (equal (time-stamp-string "%A" ref-time1) Monday))
310 ;; warned 1997-2019, changed in 2019
290 (should (equal (time-stamp-string "%^a" ref-time1) MON)) 311 (should (equal (time-stamp-string "%^a" ref-time1) MON))
291 (should (equal (time-stamp-string "%A" ref-time1) Monday))))) 312 (should (equal (time-stamp-string "%^4a" ref-time1) p4-MON)))))
292 313
293(ert-deftest time-stamp-format-month-name () 314(ert-deftest time-stamp-format-month-name ()
294 "Test time-stamp formats for month name." 315 "Test time-stamp formats for month name."
295 (with-time-stamp-test-env 316 (with-time-stamp-test-env
296 (let ((Jan (format-time-string "%b" ref-time1 t)) 317 (let* ((Jan (format-time-string "%b" ref-time1 t))
297 (JAN (format-time-string "%^b" ref-time1 t)) 318 (JAN (format-time-string "%^b" ref-time1 t))
298 (January (format-time-string "%B" ref-time1 t)) 319 (January (format-time-string "%B" ref-time1 t))
299 (JANUARY (format-time-string "%^B" ref-time1 t))) 320 (JANUARY (format-time-string "%^B" ref-time1 t))
300 ;; implemented and documented since 1997 321 (p4-Jan (string-pad Jan 4 ?\s t))
301 (should (equal (time-stamp-string "%3b" ref-time1) 322 (p4-JAN (string-pad JAN 4 ?\s t))
302 (substring January 0 3))) 323 (p10-January (string-pad January 10 ?\s t))
324 (p10-JANUARY (string-pad JANUARY 10 ?\s t)))
325 ;; implemented and recommended since 1997
303 (should (equal (time-stamp-string "%#B" ref-time1) JANUARY)) 326 (should (equal (time-stamp-string "%#B" ref-time1) JANUARY))
304 ;; documented 1997-2019 327 (should (equal (time-stamp-string "%#10B" ref-time1) p10-JANUARY))
305 (should (equal (time-stamp-string "%3B" ref-time1) 328 ;; implemented since 1997, recommended 1997-2024
306 (substring JANUARY 0 3))) 329 (should (equal (time-stamp-string "%3b" ref-time1) Jan))
330 ;; recommended 1997-2019
307 (should (equal (time-stamp-string "%:b" ref-time1) January)) 331 (should (equal (time-stamp-string "%:b" ref-time1) January))
308 ;; implemented since 2001, documented since 2019 332 ;; recommended 1997-2019, warned since 2024, will change
333 (time-stamp-should-warn
334 (should (equal (time-stamp-string "%3B" ref-time1) JAN)))
335 (time-stamp-should-warn
336 (should (equal (time-stamp-string "%10B" ref-time1) p10-JANUARY)))
337 ;; implemented since 2001, recommended since 2019
309 (should (equal (time-stamp-string "%#b" ref-time1) JAN)) 338 (should (equal (time-stamp-string "%#b" ref-time1) JAN))
339 (should (equal (time-stamp-string "%#3b" ref-time1) JAN))
340 (should (equal (time-stamp-string "%#4b" ref-time1) p4-JAN))
341 ;; implemented since 2001, recommended 2019-2024
310 (should (equal (time-stamp-string "%:B" ref-time1) January)) 342 (should (equal (time-stamp-string "%:B" ref-time1) January))
311 ;; allowed but undocumented since 2019 (warned 1997-2019) 343 ;; broken 2019-2024
344 (should (equal (time-stamp-string "%:10B" ref-time1) p10-January))
345 ;; broken in 2019, changed in 2024
346 (should (equal (time-stamp-string "%-B" ref-time1) January))
347 (should (equal (time-stamp-string "%_B" ref-time1) January))
348 ;; allowed but not recommended since 2019 (warned 1997-2019)
312 (should (equal (time-stamp-string "%^B" ref-time1) JANUARY)) 349 (should (equal (time-stamp-string "%^B" ref-time1) JANUARY))
313 ;; warned 1997-2019, changed in 2019 350 ;; warned 1997-2019, changed in 2019, recommended (with caveat) since 2024
314 (should (equal (time-stamp-string "%b" ref-time1) Jan)) 351 (should (equal (time-stamp-string "%b" ref-time1) Jan))
352 (should (equal (time-stamp-string "%4b" ref-time1) p4-Jan))
353 (should (equal (time-stamp-string "%04b" ref-time1) p4-Jan))
354 (should (equal (time-stamp-string "%B" ref-time1) January))
355 ;; warned 1997-2019, changed in 2019
315 (should (equal (time-stamp-string "%^b" ref-time1) JAN)) 356 (should (equal (time-stamp-string "%^b" ref-time1) JAN))
316 (should (equal (time-stamp-string "%B" ref-time1) January))))) 357 (should (equal (time-stamp-string "%^4b" ref-time1) p4-JAN)))))
317 358
318(ert-deftest time-stamp-format-day-of-month () 359(ert-deftest time-stamp-format-day-of-month ()
319 "Test time-stamp formats for day of month." 360 "Test time-stamp formats for day of month."
320 (with-time-stamp-test-env 361 (with-time-stamp-test-env
321 ;; implemented and documented since 1995 362 ;; implemented since 1995, recommended until 2024
322 (should (equal (time-stamp-string "%2d" ref-time1) " 2")) 363 (should (equal (time-stamp-string "%2d" ref-time1) " 2"))
323 (should (equal (time-stamp-string "%2d" ref-time2) "18")) 364 (should (equal (time-stamp-string "%2d" ref-time2) "18"))
324 (should (equal (time-stamp-string "%02d" ref-time1) "02")) 365 (should (equal (time-stamp-string "%02d" ref-time1) "02"))
325 (should (equal (time-stamp-string "%02d" ref-time2) "18")) 366 (should (equal (time-stamp-string "%02d" ref-time2) "18"))
326 ;; documented 1997-2019 367 ;; recommended 1997-2019
327 (should (equal (time-stamp-string "%:d" ref-time1) "2")) 368 (should (equal (time-stamp-string "%:d" ref-time1) "2"))
328 (should (equal (time-stamp-string "%:d" ref-time2) "18")) 369 (should (equal (time-stamp-string "%:d" ref-time2) "18"))
329 ;; implemented since 1997, documented since 2019 370 ;; implemented since 1997, recommended 2019-2024
330 (should (equal (time-stamp-string "%1d" ref-time1) "2")) 371 (should (equal (time-stamp-string "%1d" ref-time1) "2"))
331 (should (equal (time-stamp-string "%1d" ref-time2) "18")) 372 (should (equal (time-stamp-string "%1d" ref-time2) "18"))
332 ;; allowed but undocumented since 2019 (warned 1997-2019) 373 ;; warned 1997-2019, allowed 2019, recommended (with caveat) since 2024
333 (should (equal (time-stamp-string "%-d" ref-time1) "2")) 374 (should (equal (time-stamp-string "%-d" ref-time1) "2"))
334 (should (equal (time-stamp-string "%-d" ref-time2) "18")) 375 (should (equal (time-stamp-string "%-d" ref-time2) "18"))
335 ;; warned 1997-2019, changed in 2019 376 ;; warned 1997-2019, changed in 2019, recommended (with caveat) since 2024
336 (should (equal (time-stamp-string "%_d" ref-time1) " 2")) 377 (should (equal (time-stamp-string "%_d" ref-time1) " 2"))
337 (should (equal (time-stamp-string "%_d" ref-time2) "18")) 378 (should (equal (time-stamp-string "%_d" ref-time2) "18"))
338 (should (equal (time-stamp-string "%d" ref-time1) "02")) 379 (should (equal (time-stamp-string "%d" ref-time1) "02"))
@@ -341,26 +382,26 @@
341(ert-deftest time-stamp-format-hours-24 () 382(ert-deftest time-stamp-format-hours-24 ()
342 "Test time-stamp formats for hour on a 24-hour clock." 383 "Test time-stamp formats for hour on a 24-hour clock."
343 (with-time-stamp-test-env 384 (with-time-stamp-test-env
344 ;; implemented and documented since 1995 385 ;; implemented since 1995, recommended until 2024
345 (should (equal (time-stamp-string "%2H" ref-time1) "15")) 386 (should (equal (time-stamp-string "%2H" ref-time1) "15"))
346 (should (equal (time-stamp-string "%2H" ref-time2) "12")) 387 (should (equal (time-stamp-string "%2H" ref-time2) "12"))
347 (should (equal (time-stamp-string "%2H" ref-time3) " 6")) 388 (should (equal (time-stamp-string "%2H" ref-time3) " 6"))
348 (should (equal (time-stamp-string "%02H" ref-time1) "15")) 389 (should (equal (time-stamp-string "%02H" ref-time1) "15"))
349 (should (equal (time-stamp-string "%02H" ref-time2) "12")) 390 (should (equal (time-stamp-string "%02H" ref-time2) "12"))
350 (should (equal (time-stamp-string "%02H" ref-time3) "06")) 391 (should (equal (time-stamp-string "%02H" ref-time3) "06"))
351 ;; documented 1997-2019 392 ;; recommended 1997-2019
352 (should (equal (time-stamp-string "%:H" ref-time1) "15")) 393 (should (equal (time-stamp-string "%:H" ref-time1) "15"))
353 (should (equal (time-stamp-string "%:H" ref-time2) "12")) 394 (should (equal (time-stamp-string "%:H" ref-time2) "12"))
354 (should (equal (time-stamp-string "%:H" ref-time3) "6")) 395 (should (equal (time-stamp-string "%:H" ref-time3) "6"))
355 ;; implemented since 1997, documented since 2019 396 ;; implemented since 1997, recommended 2019-2024
356 (should (equal (time-stamp-string "%1H" ref-time1) "15")) 397 (should (equal (time-stamp-string "%1H" ref-time1) "15"))
357 (should (equal (time-stamp-string "%1H" ref-time2) "12")) 398 (should (equal (time-stamp-string "%1H" ref-time2) "12"))
358 (should (equal (time-stamp-string "%1H" ref-time3) "6")) 399 (should (equal (time-stamp-string "%1H" ref-time3) "6"))
359 ;; allowed but undocumented since 2019 (warned 1997-2019) 400 ;; warned 1997-2019, allowed 2019, recommended (with caveat) since 2024
360 (should (equal (time-stamp-string "%-H" ref-time1) "15")) 401 (should (equal (time-stamp-string "%-H" ref-time1) "15"))
361 (should (equal (time-stamp-string "%-H" ref-time2) "12")) 402 (should (equal (time-stamp-string "%-H" ref-time2) "12"))
362 (should (equal (time-stamp-string "%-H" ref-time3) "6")) 403 (should (equal (time-stamp-string "%-H" ref-time3) "6"))
363 ;; warned 1997-2019, changed in 2019 404 ;; warned 1997-2019, changed in 2019, recommended (with caveat) since 2024
364 (should (equal (time-stamp-string "%_H" ref-time1) "15")) 405 (should (equal (time-stamp-string "%_H" ref-time1) "15"))
365 (should (equal (time-stamp-string "%_H" ref-time2) "12")) 406 (should (equal (time-stamp-string "%_H" ref-time2) "12"))
366 (should (equal (time-stamp-string "%_H" ref-time3) " 6")) 407 (should (equal (time-stamp-string "%_H" ref-time3) " 6"))
@@ -371,26 +412,26 @@
371(ert-deftest time-stamp-format-hours-12 () 412(ert-deftest time-stamp-format-hours-12 ()
372 "Test time-stamp formats for hour on a 12-hour clock." 413 "Test time-stamp formats for hour on a 12-hour clock."
373 (with-time-stamp-test-env 414 (with-time-stamp-test-env
374 ;; implemented and documented since 1995 415 ;; implemented since 1995, recommended until 2024
375 (should (equal (time-stamp-string "%2I" ref-time1) " 3")) 416 (should (equal (time-stamp-string "%2I" ref-time1) " 3"))
376 (should (equal (time-stamp-string "%2I" ref-time2) "12")) 417 (should (equal (time-stamp-string "%2I" ref-time2) "12"))
377 (should (equal (time-stamp-string "%2I" ref-time3) " 6")) 418 (should (equal (time-stamp-string "%2I" ref-time3) " 6"))
378 (should (equal (time-stamp-string "%02I" ref-time1) "03")) 419 (should (equal (time-stamp-string "%02I" ref-time1) "03"))
379 (should (equal (time-stamp-string "%02I" ref-time2) "12")) 420 (should (equal (time-stamp-string "%02I" ref-time2) "12"))
380 (should (equal (time-stamp-string "%02I" ref-time3) "06")) 421 (should (equal (time-stamp-string "%02I" ref-time3) "06"))
381 ;; documented 1997-2019 422 ;; recommended 1997-2019
382 (should (equal (time-stamp-string "%:I" ref-time1) "3")) ;PM 423 (should (equal (time-stamp-string "%:I" ref-time1) "3")) ;PM
383 (should (equal (time-stamp-string "%:I" ref-time2) "12")) ;PM 424 (should (equal (time-stamp-string "%:I" ref-time2) "12")) ;PM
384 (should (equal (time-stamp-string "%:I" ref-time3) "6")) ;AM 425 (should (equal (time-stamp-string "%:I" ref-time3) "6")) ;AM
385 ;; implemented since 1997, documented since 2019 426 ;; implemented since 1997, recommended since 2019
386 (should (equal (time-stamp-string "%1I" ref-time1) "3")) 427 (should (equal (time-stamp-string "%1I" ref-time1) "3"))
387 (should (equal (time-stamp-string "%1I" ref-time2) "12")) 428 (should (equal (time-stamp-string "%1I" ref-time2) "12"))
388 (should (equal (time-stamp-string "%1I" ref-time3) "6")) 429 (should (equal (time-stamp-string "%1I" ref-time3) "6"))
389 ;; allowed but undocumented since 2019 (warned 1997-2019) 430 ;; warned 1997-2019, allowed 2019, recommended (with caveat) since 2024
390 (should (equal (time-stamp-string "%-I" ref-time1) "3")) 431 (should (equal (time-stamp-string "%-I" ref-time1) "3"))
391 (should (equal (time-stamp-string "%-I" ref-time2) "12")) 432 (should (equal (time-stamp-string "%-I" ref-time2) "12"))
392 (should (equal (time-stamp-string "%-I" ref-time3) "6")) 433 (should (equal (time-stamp-string "%-I" ref-time3) "6"))
393 ;; warned 1997-2019, changed in 2019 434 ;; warned 1997-2019, changed in 2019, recommended (with caveat) since 2024
394 (should (equal (time-stamp-string "%_I" ref-time1) " 3")) 435 (should (equal (time-stamp-string "%_I" ref-time1) " 3"))
395 (should (equal (time-stamp-string "%_I" ref-time2) "12")) 436 (should (equal (time-stamp-string "%_I" ref-time2) "12"))
396 (should (equal (time-stamp-string "%_I" ref-time3) " 6")) 437 (should (equal (time-stamp-string "%_I" ref-time3) " 6"))
@@ -401,21 +442,21 @@
401(ert-deftest time-stamp-format-month-number () 442(ert-deftest time-stamp-format-month-number ()
402 "Test time-stamp formats for month number." 443 "Test time-stamp formats for month number."
403 (with-time-stamp-test-env 444 (with-time-stamp-test-env
404 ;; implemented and documented since 1995 445 ;; implemented since 1995, recommended until 2024
405 (should (equal (time-stamp-string "%2m" ref-time1) " 1")) 446 (should (equal (time-stamp-string "%2m" ref-time1) " 1"))
406 (should (equal (time-stamp-string "%2m" ref-time2) "11")) 447 (should (equal (time-stamp-string "%2m" ref-time2) "11"))
407 (should (equal (time-stamp-string "%02m" ref-time1) "01")) 448 (should (equal (time-stamp-string "%02m" ref-time1) "01"))
408 (should (equal (time-stamp-string "%02m" ref-time2) "11")) 449 (should (equal (time-stamp-string "%02m" ref-time2) "11"))
409 ;; documented 1997-2019 450 ;; recommended 1997-2019
410 (should (equal (time-stamp-string "%:m" ref-time1) "1")) 451 (should (equal (time-stamp-string "%:m" ref-time1) "1"))
411 (should (equal (time-stamp-string "%:m" ref-time2) "11")) 452 (should (equal (time-stamp-string "%:m" ref-time2) "11"))
412 ;; implemented since 1997, documented since 2019 453 ;; implemented since 1997, recommended since 2019
413 (should (equal (time-stamp-string "%1m" ref-time1) "1")) 454 (should (equal (time-stamp-string "%1m" ref-time1) "1"))
414 (should (equal (time-stamp-string "%1m" ref-time2) "11")) 455 (should (equal (time-stamp-string "%1m" ref-time2) "11"))
415 ;; allowed but undocumented since 2019 (warned 1997-2019) 456 ;; warned 1997-2019, allowed 2019, recommended (with caveat) since 2024
416 (should (equal (time-stamp-string "%-m" ref-time1) "1")) 457 (should (equal (time-stamp-string "%-m" ref-time1) "1"))
417 (should (equal (time-stamp-string "%-m" ref-time2) "11")) 458 (should (equal (time-stamp-string "%-m" ref-time2) "11"))
418 ;; warned 1997-2019, changed in 2019 459 ;; warned 1997-2019, changed in 2019, recommended (with caveat) since 2024
419 (should (equal (time-stamp-string "%_m" ref-time1) " 1")) 460 (should (equal (time-stamp-string "%_m" ref-time1) " 1"))
420 (should (equal (time-stamp-string "%_m" ref-time2) "11")) 461 (should (equal (time-stamp-string "%_m" ref-time2) "11"))
421 (should (equal (time-stamp-string "%m" ref-time1) "01")) 462 (should (equal (time-stamp-string "%m" ref-time1) "01"))
@@ -424,21 +465,21 @@
424(ert-deftest time-stamp-format-minute () 465(ert-deftest time-stamp-format-minute ()
425 "Test time-stamp formats for minute." 466 "Test time-stamp formats for minute."
426 (with-time-stamp-test-env 467 (with-time-stamp-test-env
427 ;; implemented and documented since 1995 468 ;; implemented since 1995, recommended until 2024
428 (should (equal (time-stamp-string "%2M" ref-time1) " 4")) 469 (should (equal (time-stamp-string "%2M" ref-time1) " 4"))
429 (should (equal (time-stamp-string "%2M" ref-time2) "14")) 470 (should (equal (time-stamp-string "%2M" ref-time2) "14"))
430 (should (equal (time-stamp-string "%02M" ref-time1) "04")) 471 (should (equal (time-stamp-string "%02M" ref-time1) "04"))
431 (should (equal (time-stamp-string "%02M" ref-time2) "14")) 472 (should (equal (time-stamp-string "%02M" ref-time2) "14"))
432 ;; documented 1997-2019 473 ;; recommended 1997-2019
433 (should (equal (time-stamp-string "%:M" ref-time1) "4")) 474 (should (equal (time-stamp-string "%:M" ref-time1) "4"))
434 (should (equal (time-stamp-string "%:M" ref-time2) "14")) 475 (should (equal (time-stamp-string "%:M" ref-time2) "14"))
435 ;; implemented since 1997, documented since 2019 476 ;; implemented since 1997, recommended since 2019
436 (should (equal (time-stamp-string "%1M" ref-time1) "4")) 477 (should (equal (time-stamp-string "%1M" ref-time1) "4"))
437 (should (equal (time-stamp-string "%1M" ref-time2) "14")) 478 (should (equal (time-stamp-string "%1M" ref-time2) "14"))
438 ;; allowed but undocumented since 2019 (warned 1997-2019) 479 ;; warned 1997-2019, allowed 2019, recommended (with caveat) since 2024
439 (should (equal (time-stamp-string "%-M" ref-time1) "4")) 480 (should (equal (time-stamp-string "%-M" ref-time1) "4"))
440 (should (equal (time-stamp-string "%-M" ref-time2) "14")) 481 (should (equal (time-stamp-string "%-M" ref-time2) "14"))
441 ;; warned 1997-2019, changed in 2019 482 ;; warned 1997-2019, changed in 2019, recommended (with caveat) since 2024
442 (should (equal (time-stamp-string "%_M" ref-time1) " 4")) 483 (should (equal (time-stamp-string "%_M" ref-time1) " 4"))
443 (should (equal (time-stamp-string "%_M" ref-time2) "14")) 484 (should (equal (time-stamp-string "%_M" ref-time2) "14"))
444 (should (equal (time-stamp-string "%M" ref-time1) "04")) 485 (should (equal (time-stamp-string "%M" ref-time1) "04"))
@@ -447,21 +488,21 @@
447(ert-deftest time-stamp-format-second () 488(ert-deftest time-stamp-format-second ()
448 "Test time-stamp formats for second." 489 "Test time-stamp formats for second."
449 (with-time-stamp-test-env 490 (with-time-stamp-test-env
450 ;; implemented and documented since 1995 491 ;; implemented since 1995, recommended until 2024
451 (should (equal (time-stamp-string "%2S" ref-time1) " 5")) 492 (should (equal (time-stamp-string "%2S" ref-time1) " 5"))
452 (should (equal (time-stamp-string "%2S" ref-time2) "15")) 493 (should (equal (time-stamp-string "%2S" ref-time2) "15"))
453 (should (equal (time-stamp-string "%02S" ref-time1) "05")) 494 (should (equal (time-stamp-string "%02S" ref-time1) "05"))
454 (should (equal (time-stamp-string "%02S" ref-time2) "15")) 495 (should (equal (time-stamp-string "%02S" ref-time2) "15"))
455 ;; documented 1997-2019 496 ;; recommended 1997-2019
456 (should (equal (time-stamp-string "%:S" ref-time1) "5")) 497 (should (equal (time-stamp-string "%:S" ref-time1) "5"))
457 (should (equal (time-stamp-string "%:S" ref-time2) "15")) 498 (should (equal (time-stamp-string "%:S" ref-time2) "15"))
458 ;; implemented since 1997, documented since 2019 499 ;; implemented since 1997, recommended since 2019
459 (should (equal (time-stamp-string "%1S" ref-time1) "5")) 500 (should (equal (time-stamp-string "%1S" ref-time1) "5"))
460 (should (equal (time-stamp-string "%1S" ref-time2) "15")) 501 (should (equal (time-stamp-string "%1S" ref-time2) "15"))
461 ;; allowed but undocumented since 2019 (warned 1997-2019) 502 ;; warned 1997-2019, allowed 2019, recommended (with caveat) since 2024
462 (should (equal (time-stamp-string "%-S" ref-time1) "5")) 503 (should (equal (time-stamp-string "%-S" ref-time1) "5"))
463 (should (equal (time-stamp-string "%-S" ref-time2) "15")) 504 (should (equal (time-stamp-string "%-S" ref-time2) "15"))
464 ;; warned 1997-2019, changed in 2019 505 ;; warned 1997-2019, changed in 2019, recommended (with caveat) since 2024
465 (should (equal (time-stamp-string "%_S" ref-time1) " 5")) 506 (should (equal (time-stamp-string "%_S" ref-time1) " 5"))
466 (should (equal (time-stamp-string "%_S" ref-time2) "15")) 507 (should (equal (time-stamp-string "%_S" ref-time2) "15"))
467 (should (equal (time-stamp-string "%S" ref-time1) "05")) 508 (should (equal (time-stamp-string "%S" ref-time1) "05"))
@@ -470,12 +511,14 @@
470(ert-deftest time-stamp-format-year-2digit () 511(ert-deftest time-stamp-format-year-2digit ()
471 "Test time-stamp formats for %y." 512 "Test time-stamp formats for %y."
472 (with-time-stamp-test-env 513 (with-time-stamp-test-env
473 ;; implemented and documented since 1995 514 ;; implemented since 1995, recommended 1995-2024
474 (should (equal (time-stamp-string "%02y" ref-time1) "06")) 515 (should (equal (time-stamp-string "%02y" ref-time1) "06"))
475 (should (equal (time-stamp-string "%02y" ref-time2) "16")) 516 (should (equal (time-stamp-string "%02y" ref-time2) "16"))
476 ;; documented 1997-2019 517 ;; recommended 1997-2019, warned since 2024
477 (should (equal (time-stamp-string "%:y" ref-time1) "2006")) 518 (time-stamp-should-warn
478 (should (equal (time-stamp-string "%:y" ref-time2) "2016")) 519 (should (equal (time-stamp-string "%:y" ref-time1) "2006")))
520 (time-stamp-should-warn
521 (should (equal (time-stamp-string "%:y" ref-time2) "2016")))
479 ;; warned 1997-2019, changed in 2019 522 ;; warned 1997-2019, changed in 2019
480 ;; (We don't expect the %-y or %_y form to be useful, 523 ;; (We don't expect the %-y or %_y form to be useful,
481 ;; but we test both so that we can confidently state that 524 ;; but we test both so that we can confidently state that
@@ -484,6 +527,7 @@
484 (should (equal (time-stamp-string "%-y" ref-time2) "16")) 527 (should (equal (time-stamp-string "%-y" ref-time2) "16"))
485 (should (equal (time-stamp-string "%_y" ref-time1) " 6")) 528 (should (equal (time-stamp-string "%_y" ref-time1) " 6"))
486 (should (equal (time-stamp-string "%_y" ref-time2) "16")) 529 (should (equal (time-stamp-string "%_y" ref-time2) "16"))
530 ;; warned 1997-2019, changed in 2019, recommended (with caveat) since 2024
487 (should (equal (time-stamp-string "%y" ref-time1) "06")) 531 (should (equal (time-stamp-string "%y" ref-time1) "06"))
488 (should (equal (time-stamp-string "%y" ref-time2) "16")) 532 (should (equal (time-stamp-string "%y" ref-time2) "16"))
489 ;; implemented since 1995, warned since 2019, will change 533 ;; implemented since 1995, warned since 2019, will change
@@ -495,7 +539,7 @@
495(ert-deftest time-stamp-format-year-4digit () 539(ert-deftest time-stamp-format-year-4digit ()
496 "Test time-stamp format %Y." 540 "Test time-stamp format %Y."
497 (with-time-stamp-test-env 541 (with-time-stamp-test-env
498 ;; implemented since 1997, documented since 2019 542 ;; implemented since 1997, recommended since 2019
499 (should (equal (time-stamp-string "%Y" ref-time1) "2006")) 543 (should (equal (time-stamp-string "%Y" ref-time1) "2006"))
500 ;; numbers do not truncate 544 ;; numbers do not truncate
501 (should (equal (time-stamp-string "%2Y" ref-time1) "2006")) 545 (should (equal (time-stamp-string "%2Y" ref-time1) "2006"))
@@ -510,15 +554,16 @@
510 (Am (format-time-string "%p" ref-time3 t)) 554 (Am (format-time-string "%p" ref-time3 t))
511 (PM (format-time-string "%^p" ref-time1 t)) 555 (PM (format-time-string "%^p" ref-time1 t))
512 (AM (format-time-string "%^p" ref-time3 t))) 556 (AM (format-time-string "%^p" ref-time3 t)))
513 ;; implemented and documented since 1997 557 ;; implemented and recommended since 1997
514 (should (equal (time-stamp-string "%#p" ref-time1) pm)) 558 (should (equal (time-stamp-string "%#p" ref-time1) pm))
515 (should (equal (time-stamp-string "%#p" ref-time3) am)) 559 (should (equal (time-stamp-string "%#p" ref-time3) am))
560 ;; implemented since 1997, recommended 1997-2024
516 (should (equal (time-stamp-string "%P" ref-time1) Pm)) 561 (should (equal (time-stamp-string "%P" ref-time1) Pm))
517 (should (equal (time-stamp-string "%P" ref-time3) Am)) 562 (should (equal (time-stamp-string "%P" ref-time3) Am))
518 ;; implemented since 1997 563 ;; implemented since 1997
519 (should (equal (time-stamp-string "%^#p" ref-time1) pm)) 564 (should (equal (time-stamp-string "%^#p" ref-time1) pm))
520 (should (equal (time-stamp-string "%^#p" ref-time3) am)) 565 (should (equal (time-stamp-string "%^#p" ref-time3) am))
521 ;; warned 1997-2019, changed in 2019 566 ;; warned 1997-2019, changed in 2019, recommended (with caveat) since 2024
522 (should (equal (time-stamp-string "%p" ref-time1) Pm)) 567 (should (equal (time-stamp-string "%p" ref-time1) Pm))
523 (should (equal (time-stamp-string "%p" ref-time3) Am)) 568 (should (equal (time-stamp-string "%p" ref-time3) Am))
524 ;; changed in 2024 569 ;; changed in 2024
@@ -543,19 +588,22 @@
543 (with-time-stamp-test-env 588 (with-time-stamp-test-env
544 (let ((UTC-abbr (format-time-string "%Z" ref-time1 t)) 589 (let ((UTC-abbr (format-time-string "%Z" ref-time1 t))
545 (utc-abbr (format-time-string "%#Z" ref-time1 t))) 590 (utc-abbr (format-time-string "%#Z" ref-time1 t)))
546 ;; implemented and documented since 1995 591 ;; implemented and recommended since 1995
547 (should (equal (time-stamp-string "%Z" ref-time1) UTC-abbr)) 592 (should (equal (time-stamp-string "%Z" ref-time1) UTC-abbr))
548 ;; implemented since 1997, documented since 2019 593 ;; implemented since 1997, recommended since 2019
549 (should (equal (time-stamp-string "%#Z" ref-time1) utc-abbr))))) 594 (should (equal (time-stamp-string "%#Z" ref-time1) utc-abbr))
595 ;; ^ accepted and ignored since 1995/1997, test for consistency with %p
596 (should (equal (time-stamp-string "%^Z" ref-time1) UTC-abbr))
597 (should (equal (time-stamp-string "%^#Z" ref-time1) utc-abbr)))))
550 598
551(ert-deftest time-stamp-format-time-zone-offset () 599(ert-deftest time-stamp-format-time-zone-offset ()
552 "Test time-stamp legacy format %z and spot-test new offset format %5z." 600 "Test time-stamp legacy format %z and spot-test new offset format %5z."
553 (with-time-stamp-test-env 601 (with-time-stamp-test-env
554 (let ((utc-abbr (format-time-string "%#Z" ref-time1 t))) 602 (let ((utc-abbr (format-time-string "%#Z" ref-time1 t)))
555 ;; documented 1995-2019, warned since 2019, will change 603 ;; recommended 1995-2019, warned since 2019, will change
556 (time-stamp-should-warn 604 (time-stamp-should-warn
557 (equal (time-stamp-string "%z" ref-time1) utc-abbr))) 605 (equal (time-stamp-string "%z" ref-time1) utc-abbr)))
558 ;; implemented and documented (with compat caveat) since 2019 606 ;; implemented and recommended (with compat caveat) since 2019
559 (should (equal (time-stamp-string "%5z" ref-time1) "+0000")) 607 (should (equal (time-stamp-string "%5z" ref-time1) "+0000"))
560 (let ((time-stamp-time-zone "PST8")) 608 (let ((time-stamp-time-zone "PST8"))
561 (should (equal (time-stamp-string "%5z" ref-time1) "-0800"))) 609 (should (equal (time-stamp-string "%5z" ref-time1) "-0800")))
@@ -563,20 +611,21 @@
563 (should (equal (time-stamp-string "%5z" ref-time1) "-1000"))) 611 (should (equal (time-stamp-string "%5z" ref-time1) "-1000")))
564 (let ((time-stamp-time-zone "CET-1")) 612 (let ((time-stamp-time-zone "CET-1"))
565 (should (equal (time-stamp-string "%5z" ref-time1) "+0100"))) 613 (should (equal (time-stamp-string "%5z" ref-time1) "+0100")))
566 ;; implemented since 2019, verify that these don't warn 614 ;; implemented since 2019, recommended (with compat caveat) since 2024
567 ;; See also the "formatz" tests below, which since 2021 test more 615 ;; See also the "formatz" tests below, which since 2021 test more
568 ;; variants with more offsets. 616 ;; variants with more offsets.
569 (should (equal (time-stamp-string "%-z" ref-time1) "+00")) 617 (should (equal (time-stamp-string "%-z" ref-time1) "+00"))
618 (should (equal (time-stamp-string "%:::z" ref-time1) "+00"))
570 (should (equal (time-stamp-string "%:z" ref-time1) "+00:00")) 619 (should (equal (time-stamp-string "%:z" ref-time1) "+00:00"))
620 ;; implemented since 2019
571 (should (equal (time-stamp-string "%::z" ref-time1) "+00:00:00")) 621 (should (equal (time-stamp-string "%::z" ref-time1) "+00:00:00"))
572 (should (equal (time-stamp-string "%9::z" ref-time1) "+00:00:00")) 622 (should (equal (time-stamp-string "%9::z" ref-time1) "+00:00:00"))))
573 (should (equal (time-stamp-string "%:::z" ref-time1) "+00"))))
574 623
575(ert-deftest time-stamp-format-non-date-conversions () 624(ert-deftest time-stamp-format-non-date-conversions ()
576 "Test time-stamp formats for non-date items." 625 "Test time-stamp formats for non-date items."
577 (with-time-stamp-test-env 626 (with-time-stamp-test-env
578 (with-time-stamp-system-name "test-system-name.example.org" 627 (with-time-stamp-system-name "test-system-name.example.org"
579 ;; implemented and documented since 1995 628 ;; implemented and recommended since 1995
580 (should (equal (time-stamp-string "%%" ref-time1) "%")) ;% last char 629 (should (equal (time-stamp-string "%%" ref-time1) "%")) ;% last char
581 (should (equal (time-stamp-string "%%P" ref-time1) "%P")) ;% not last char 630 (should (equal (time-stamp-string "%%P" ref-time1) "%P")) ;% not last char
582 (should (equal (time-stamp-string "%f" ref-time1) "time-stamped-file")) 631 (should (equal (time-stamp-string "%f" ref-time1) "time-stamped-file"))
@@ -589,15 +638,18 @@
589 (let ((mail-host-address nil)) 638 (let ((mail-host-address nil))
590 (should (equal (time-stamp-string "%h" ref-time1) 639 (should (equal (time-stamp-string "%h" ref-time1)
591 "test-system-name.example.org"))) 640 "test-system-name.example.org")))
592 ;; documented 1995-2019 641 ;; recommended 1997-2019, warned since 2024
593 (should (equal (time-stamp-string "%s" ref-time1) 642 (time-stamp-should-warn
594 "test-system-name.example.org")) 643 (should (equal (time-stamp-string "%s" ref-time1)
595 (should (equal (time-stamp-string "%U" ref-time1) "100%d Tester")) 644 "test-system-name.example.org")))
596 (should (equal (time-stamp-string "%u" ref-time1) "test-logname")) 645 (time-stamp-should-warn
597 ;; implemented since 2001, documented since 2019 646 (should (equal (time-stamp-string "%U" ref-time1) "100%d Tester")))
647 (time-stamp-should-warn
648 (should (equal (time-stamp-string "%u" ref-time1) "test-logname")))
649 ;; implemented since 2001, recommended since 2019
598 (should (equal (time-stamp-string "%L" ref-time1) "100%d Tester")) 650 (should (equal (time-stamp-string "%L" ref-time1) "100%d Tester"))
599 (should (equal (time-stamp-string "%l" ref-time1) "test-logname")) 651 (should (equal (time-stamp-string "%l" ref-time1) "test-logname"))
600 ;; implemented since 2007, documented since 2019 652 ;; implemented since 2007, recommended since 2019
601 (should (equal (time-stamp-string "%Q" ref-time1) 653 (should (equal (time-stamp-string "%Q" ref-time1)
602 "test-system-name.example.org")) 654 "test-system-name.example.org"))
603 (should (equal (time-stamp-string "%q" ref-time1) "test-system-name"))) 655 (should (equal (time-stamp-string "%q" ref-time1) "test-system-name")))
@@ -668,24 +720,20 @@
668(ert-deftest time-stamp-format-string-width () 720(ert-deftest time-stamp-format-string-width ()
669 "Test time-stamp string width modifiers." 721 "Test time-stamp string width modifiers."
670 (with-time-stamp-test-env 722 (with-time-stamp-test-env
671 (let ((May (format-time-string "%b" ref-time3 t)) 723 (let ((UTC-abbr (format-time-string "%Z" ref-time1 t)))
672 (SUN (format-time-string "%^a" ref-time3 t)) 724 (should (equal (time-stamp-string "%1%" ref-time3) "%"))
673 (NOV (format-time-string "%^b" ref-time2 t))) 725 (should (equal (time-stamp-string "%2%" ref-time3) " %"))
674 ;; strings truncate on the right or are blank-padded on the left 726 (should (equal (time-stamp-string "%9%" ref-time3) " %"))
675 (should (equal (time-stamp-string "%0b" ref-time3) "")) 727 (should (equal (time-stamp-string "%10%" ref-time3) " %"))
676 (should (equal (time-stamp-string "%1b" ref-time3) (substring May 0 1))) 728 (should (equal (time-stamp-string "%03d" ref-time3) "025"))
677 (should (equal (time-stamp-string "%2b" ref-time3) (substring May 0 2))) 729 (should (equal (time-stamp-string "%3d" ref-time3) " 25"))
678 (should (equal (time-stamp-string "%3b" ref-time3) (substring May 0 3))) 730 (should (equal (time-stamp-string "%_3d" ref-time3) " 25"))
679 (should (equal (time-stamp-string "%4b" ref-time3) (concat " " May))) 731 ;; since 2024
680 (should (equal (time-stamp-string "%0%" ref-time3) "")) 732 (should (equal (time-stamp-string "%0d" ref-time1) "02"))
681 (should (equal (time-stamp-string "%1%" ref-time3) "%")) 733 (should (equal (time-stamp-string "%0d" ref-time2) "18"))
682 (should (equal (time-stamp-string "%2%" ref-time3) " %")) 734 ;; broken 2019-2024
683 (should (equal (time-stamp-string "%9%" ref-time3) " %")) 735 (should (equal (time-stamp-string "%-Z" ref-time1) UTC-abbr))
684 (should (equal (time-stamp-string "%10%" ref-time3) " %")) 736 (should (equal (time-stamp-string "%_Z" ref-time1) UTC-abbr)))))
685 (should (equal (time-stamp-string "%#3a" ref-time3)
686 (substring SUN 0 3)))
687 (should (equal (time-stamp-string "%#3b" ref-time2)
688 (substring NOV 0 3))))))
689 737
690;;; Tests of helper functions 738;;; Tests of helper functions
691 739
@@ -895,11 +943,11 @@ The functions in `pattern-mod' are composed left to right."
895 943
896(defun formatz-mod-pad-r10 (string) 944(defun formatz-mod-pad-r10 (string)
897 "Return STRING padded on the right to 10 characters." 945 "Return STRING padded on the right to 10 characters."
898 (concat string (make-string (- 10 (length string)) ?\s))) 946 (string-pad string 10))
899 947
900(defun formatz-mod-pad-r12 (string) 948(defun formatz-mod-pad-r12 (string)
901 "Return STRING padded on the right to 12 characters." 949 "Return STRING padded on the right to 12 characters."
902 (concat string (make-string (- 12 (length string)) ?\s))) 950 (string-pad string 12))
903 951
904;; Convenience macro for generating groups of test cases. 952;; Convenience macro for generating groups of test cases.
905 953
@@ -966,7 +1014,7 @@ the other expected results for hours greater than 99 with non-zero seconds."
966 1014
967;;;; The actual test cases for %z 1015;;;; The actual test cases for %z
968 1016
969;;; %z formats without colons. 1017;;; Test %z formats without colons.
970 1018
971;; Option character "-" (minus) minimizes; it removes "00" minutes. 1019;; Option character "-" (minus) minimizes; it removes "00" minutes.
972(formatz-generate-tests ("%-z" "%-3z") 1020(formatz-generate-tests ("%-z" "%-3z")
@@ -976,7 +1024,7 @@ the other expected results for hours greater than 99 with non-zero seconds."
976 ("+100:00") 1024 ("+100:00")
977 ("+100:00:30")) 1025 ("+100:00:30"))
978 1026
979;; Tests that minus with padding pads with spaces. 1027;; Minus with padding pads with spaces.
980(formatz-generate-tests ("%-12z") 1028(formatz-generate-tests ("%-12z")
981 ("+00 " formatz-mod-pad-r12) 1029 ("+00 " formatz-mod-pad-r12)
982 ("+0030 " formatz-mod-del-colons formatz-mod-pad-r12) 1030 ("+0030 " formatz-mod-del-colons formatz-mod-pad-r12)
@@ -984,7 +1032,7 @@ the other expected results for hours greater than 99 with non-zero seconds."
984 ("+100:00 " formatz-mod-pad-r12) 1032 ("+100:00 " formatz-mod-pad-r12)
985 ("+100:00:30 " formatz-mod-pad-r12)) 1033 ("+100:00:30 " formatz-mod-pad-r12))
986 1034
987;; Tests that 0 after other digits becomes padding of ten, not zero flag. 1035;; 0 after other digits becomes padding of ten, not zero flag.
988(formatz-generate-tests ("%-10z") 1036(formatz-generate-tests ("%-10z")
989 ("+00 " formatz-mod-pad-r10) 1037 ("+00 " formatz-mod-pad-r10)
990 ("+0030 " formatz-mod-del-colons formatz-mod-pad-r10) 1038 ("+0030 " formatz-mod-del-colons formatz-mod-pad-r10)
@@ -1017,7 +1065,7 @@ the other expected results for hours greater than 99 with non-zero seconds."
1017 ("+100:00") 1065 ("+100:00")
1018 ("+100:00:30")) 1066 ("+100:00:30"))
1019 1067
1020;; Tests that padding adds spaces. 1068;; Padding adds spaces.
1021(formatz-generate-tests ("%12z") 1069(formatz-generate-tests ("%12z")
1022 ("+0000 " formatz-mod-add-00 formatz-mod-pad-r12) 1070 ("+0000 " formatz-mod-add-00 formatz-mod-pad-r12)
1023 ("+0030 " formatz-mod-del-colons formatz-mod-pad-r12) 1071 ("+0030 " formatz-mod-del-colons formatz-mod-pad-r12)
@@ -1049,7 +1097,7 @@ the other expected results for hours greater than 99 with non-zero seconds."
1049 ("+100:00:00 " formatz-mod-add-colon00 formatz-mod-pad-r12) 1097 ("+100:00:00 " formatz-mod-add-colon00 formatz-mod-pad-r12)
1050 ("+100:00:30 " formatz-mod-pad-r12)) 1098 ("+100:00:30 " formatz-mod-pad-r12))
1051 1099
1052;;; %z formats with colons 1100;;; Test %z formats with colons.
1053 1101
1054;; Three colons can output hours only, 1102;; Three colons can output hours only,
1055;; like %-z, but uses colons with non-zero minutes and seconds. 1103;; like %-z, but uses colons with non-zero minutes and seconds.
@@ -1061,14 +1109,15 @@ the other expected results for hours greater than 99 with non-zero seconds."
1061 ("+100:00") 1109 ("+100:00")
1062 ("+100:00:30")) 1110 ("+100:00:30"))
1063 1111
1064;; Padding with three colons adds spaces 1112;; Padding with three colons adds spaces.
1065(formatz-generate-tests ("%12:::z") 1113(formatz-generate-tests ("%12:::z")
1066 ("+00 " formatz-mod-pad-r12) 1114 ("+00 " formatz-mod-pad-r12)
1067 ("+00:30 " formatz-mod-pad-r12) 1115 ("+00:30 " formatz-mod-pad-r12)
1068 ("+00:00:30 " formatz-mod-pad-r12) 1116 ("+00:00:30 " formatz-mod-pad-r12)
1069 ("+100:00 " formatz-mod-pad-r12) 1117 ("+100:00 " formatz-mod-pad-r12)
1070 ("+100:00:30 " formatz-mod-pad-r12)) 1118 ("+100:00:30 " formatz-mod-pad-r12))
1071;; Tests that 0 after other digits becomes padding of ten, not zero flag. 1119
1120;; 0 after other digits becomes padding of ten, not zero flag.
1072(formatz-generate-tests ("%10:::z") 1121(formatz-generate-tests ("%10:::z")
1073 ("+00 " formatz-mod-pad-r10) 1122 ("+00 " formatz-mod-pad-r10)
1074 ("+00:30 " formatz-mod-pad-r10) 1123 ("+00:30 " formatz-mod-pad-r10)
@@ -1084,7 +1133,7 @@ the other expected results for hours greater than 99 with non-zero seconds."
1084 ("+100:00") 1133 ("+100:00")
1085 ("+100:00:30")) 1134 ("+100:00:30"))
1086 1135
1087;; Padding with one colon adds spaces 1136;; Padding with one colon adds spaces.
1088(formatz-generate-tests ("%12:z") 1137(formatz-generate-tests ("%12:z")
1089 ("+00:00 " formatz-mod-add-colon00 formatz-mod-pad-r12) 1138 ("+00:00 " formatz-mod-add-colon00 formatz-mod-pad-r12)
1090 ("+00:30 " formatz-mod-pad-r12) 1139 ("+00:30 " formatz-mod-pad-r12)
@@ -1117,7 +1166,7 @@ the other expected results for hours greater than 99 with non-zero seconds."
1117 ("+100:00:00 " formatz-mod-add-colon00 formatz-mod-pad-r12) 1166 ("+100:00:00 " formatz-mod-add-colon00 formatz-mod-pad-r12)
1118 ("+100:00:30 " formatz-mod-pad-r12)) 1167 ("+100:00:30 " formatz-mod-pad-r12))
1119 1168
1120;;; Illegal %z formats 1169;;; Test illegal %z formats.
1121 1170
1122(ert-deftest formatz-illegal-options () 1171(ert-deftest formatz-illegal-options ()
1123 "Test that illegal/nonsensical/ambiguous %z formats don't produce output." 1172 "Test that illegal/nonsensical/ambiguous %z formats don't produce output."