From: Stephen Gildea Date: Tue, 10 Dec 2024 17:09:39 +0000 (-0800) Subject: time-stamp: properly abbreviate instead of truncating names X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=7012e5a33ce3a664a5060c646f1be1169a4d9dee;p=emacs.git 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. (cherry picked from commit 7665ec8df8d1c01211db6a85dda4813d6912ffee) --- 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 @@ :group 'extensions) -(defcustom time-stamp-format "%Y-%02m-%02d %02H:%02M:%02S %l" +(defcustom time-stamp-format "%Y-%m-%d %H:%M:%S %l" "Format of the string inserted by \\[time-stamp]. -This is a string, used verbatim except for character sequences beginning -with %, as follows. - -%:A weekday name: `Monday' %#A gives uppercase: `MONDAY' -%3a abbreviated weekday: `Mon' %#a gives uppercase: `MON' -%:B month name: `January' %#B gives uppercase: `JANUARY' -%3b abbreviated month: `Jan' %#b gives uppercase: `JAN' -%02d day of month -%02H 24-hour clock hour -%02I 12-hour clock hour -%02m month number -%02M minute -%#p `am' or `pm' %P gives uppercase: `AM' or `PM' -%02S seconds +The string is inserted verbatim except for character sequences beginning +with %, which are converted as follows: + +%A weekday name: `Monday' %a abbreviated weekday name: `Mon' +%B month name: `January' %b abbreviated month name: `Jan' +%d day of month +%H 24-hour clock hour %I 12-hour clock hour +%m month number +%M minute +%p `AM' or `PM' +%S seconds %w day number of week, Sunday is 0 -%02y 2-digit year %Y 4-digit year -%Z time zone name: `EST' %#Z gives lowercase: `est' -%5z time zone offset: `-0500' (since Emacs 27; see note below) +%Y 4-digit year %y 2-digit year +%Z time zone name: `EST' +%-z zone offset with hour: `-08' %:::z adds colons as needed: `+05:30' +%5z zone offset with mins: `-0800' %:z adds colon: `-08:00' Non-date items: -%% a literal percent character: `%' -%f file name without directory %F absolute file name -%l login name %L full name of logged-in user -%q unqualified host name %Q fully-qualified host name +%% literal percent character: \"%\" +%f file name without directory %F absolute file name +%l login name %L full name of logged-in user +%q unqualified host name %Q fully-qualified host name %h mail host name -Decimal digits between the % and the type character specify the -field width. Strings are truncated on the right. -A leading zero in the field width zero-fills a number. +A \"#\" after the % changes the case of letters. For example, on Mondays, +in the default locale, \"%#A\" converts to \"MONDAY\". -For example, to get a common format used by the `date' command, -use \"%3a %3b %2d %02H:%02M:%02S %Z %Y\". +Decimal digits before the type character specify the minimum field +width. A \"0\" before the field width adds insignificant zeroes +as appropriate, otherwise the padding is done with spaces. + +If no padding is specified, a field that can be one or two digits is padded +with \"0\" to two digits if necessary. Follow the % with \"_\" to pad with a +space instead, or follow it with \"-\" to suppress this padding entirely. +Thus, on the 5th of the month, the day is converted as follows: + +\"%d\" -> \"05\" +\"%_d\" -> \" 5\" +\"%-d\" -> \"5\" + +For example, to get a common format used by the \"date\" command, +use \"%a %b %_d %H:%M:%S %Z %Y\". The values of non-numeric formatted items depend on the locale setting recorded in `system-time-locale' and `locale-coding-system'. -The examples here are for the default (`C') locale. +The examples here are for the default (\"C\") locale. `time-stamp-time-zone' controls the time zone used. -The default padding of some formats has changed to be more compatible -with format-time-string. To be compatible with older versions of Emacs, -specify a padding width (as shown) or use the : modifier to request the -transitional behavior (again, as shown). - -The behavior of `%5z' is new in Emacs 27. If your files might be -edited by older versions of Emacs also, do not use this format yet." +Some of the conversions recommended here work only in Emacs 27 or later. +If your files might be edited by older versions of Emacs also, you should +limit yourself to the formats recommended by that older version." :type 'string :version "27.1") ;;;###autoload(put 'time-stamp-format 'safe-local-variable 'stringp) @@ -273,11 +279,11 @@ Examples: // time-stamp-pattern: \"-9/^Last modified: %%$\" (sets `time-stamp-line-limit', `time-stamp-start' and `time-stamp-end') -@c time-stamp-pattern: \"@set Time-stamp: %:B %1d, %Y$\" +@c time-stamp-pattern: \"@set Time-stamp: %B %-d, %Y$\" (sets `time-stamp-start', `time-stamp-format' and `time-stamp-end') %% time-stamp-pattern: \"newcommand{\\\\\\\\timestamp}{%%}\" - (sets `time-stamp-start'and `time-stamp-end') + (sets `time-stamp-start' and `time-stamp-end') See also `time-stamp-count' and `time-stamp-inserts-lines'.") @@ -483,7 +489,7 @@ normally the current time is used." ;;; At all times, all the formats recommended in the doc string ;;; of time-stamp-format will work not only in the current version of ;;; Emacs, but in all versions that have been released within the past -;;; two years. +;;; five years. ;;; The : modifier is a temporary conversion feature used to resolve ;;; ambiguous formats--formats that are changing (over time) incompatibly. (defun time-stamp-string-preprocess (format &optional time) @@ -576,10 +582,22 @@ and all `time-stamp-format' compatibility." (time-stamp--format "%#a" time) (time-stamp--format "%a" time)))) ((eq cur-char ?A) - (if (or change-case upcase (not (string-equal field-width - ""))) - (time-stamp--format "%#A" time) - (time-stamp--format "%A" time))) + (if (and (>= (string-to-number field-width) 1) + (<= (string-to-number field-width) 3) + (not flag-minimize) + (not flag-pad-with-spaces)) + (progn + (time-stamp-conv-warn "%3A" "%#a") + (time-stamp--format "%#a" time)) + (if (or change-case upcase) + (time-stamp--format "%#A" time) + (if (or (> alt-form 0) + flag-minimize flag-pad-with-spaces + (string-equal field-width "")) + (time-stamp--format "%A" time) + (time-stamp-conv-warn (format "%%%sA" field-width) + (format "%%#%sA" field-width)) + (time-stamp--format "%#A" time))))) ((eq cur-char ?b) ;month name (if (> alt-form 0) (if (string-equal field-width "") @@ -589,10 +607,22 @@ and all `time-stamp-format' compatibility." (time-stamp--format "%#b" time) (time-stamp--format "%b" time)))) ((eq cur-char ?B) - (if (or change-case upcase (not (string-equal field-width - ""))) - (time-stamp--format "%#B" time) - (time-stamp--format "%B" time))) + (if (and (>= (string-to-number field-width) 1) + (<= (string-to-number field-width) 3) + (not flag-minimize) + (not flag-pad-with-spaces)) + (progn + (time-stamp-conv-warn "%3B" "%#b") + (time-stamp--format "%#b" time)) + (if (or change-case upcase) + (time-stamp--format "%#B" time) + (if (or (> alt-form 0) + flag-minimize flag-pad-with-spaces + (string-equal field-width "")) + (time-stamp--format "%B" time) + (time-stamp-conv-warn (format "%%%sB" field-width) + (format "%%#%sB" field-width)) + (time-stamp--format "%#B" time))))) ((eq cur-char ?d) ;day of month, 1-31 (time-stamp-do-number cur-char alt-form field-width time)) ((eq cur-char ?H) ;hour, 0-23 @@ -620,13 +650,15 @@ and all `time-stamp-format' compatibility." ((eq cur-char ?w) ;weekday number, Sunday is 0 (time-stamp--format "%w" time)) ((eq cur-char ?y) ;year - (if (> alt-form 0) - (string-to-number (time-stamp--format "%Y" time)) - (if (or (string-equal field-width "") - (<= (string-to-number field-width) 2)) - (string-to-number (time-stamp--format "%y" time)) - (time-stamp-conv-warn (format "%%%sy" field-width) "%Y") - (string-to-number (time-stamp--format "%Y" time))))) + (if (= alt-form 0) + (if (or (string-equal field-width "") + (<= (string-to-number field-width) 2)) + (string-to-number (time-stamp--format "%y" time)) + (time-stamp-conv-warn + (format "%%%sy" field-width) "%Y") + (string-to-number (time-stamp--format "%Y" time))) + (time-stamp-conv-warn "%:y" "%Y") + (string-to-number (time-stamp--format "%Y" time)))) ((eq cur-char ?Y) ;4-digit year (string-to-number (time-stamp--format "%Y" time))) ((eq cur-char ?z) ;time zone offset @@ -673,10 +705,13 @@ and all `time-stamp-format' compatibility." (or buffer-file-name time-stamp-no-file)) ((eq cur-char ?s) ;system name, legacy + (time-stamp-conv-warn "%s" "%Q") (system-name)) ((eq cur-char ?u) ;user name, legacy + (time-stamp-conv-warn "%u" "%l") (user-login-name)) ((eq cur-char ?U) ;user full name, legacy + (time-stamp-conv-warn "%U" "%L") (user-full-name)) ((eq cur-char ?l) ;login name (user-login-name)) @@ -694,25 +729,14 @@ and all `time-stamp-format' compatibility." )) (and (numberp field-result) (= alt-form 0) - (string-equal field-width "") + (or (string-equal field-width "") + (string-equal field-width "0")) ;; no width provided; set width for default (setq field-width "02")) - (let ((padded-result - (format (format "%%%s%c" - field-width - (if (numberp field-result) ?d ?s)) - (or field-result "")))) - (let* ((initial-length (length padded-result)) - (desired-length (if (string-equal field-width "") - initial-length - (string-to-number field-width)))) - (if (> initial-length desired-length) - ;; truncate strings on right - (if (and (stringp field-result) - (not (eq cur-char ?z))) ;offset does not truncate - (substring padded-result 0 desired-length) - padded-result) ;numbers don't truncate - padded-result))))) + (format (format "%%%s%c" + field-width + (if (numberp field-result) ?d ?s)) + (or field-result "")))) (t (char-to-string cur-char))))) (setq ind (1+ ind))) @@ -883,7 +907,7 @@ OFFSET-SECS is the time zone offset (in seconds east of UTC) to be formatted according to the preceding parameters. This is an internal function used by `time-stamp'." - ;; The caller of this function must have already parsed the %z + ;; Callers of this function need to have already parsed the %z ;; format string; this function accepts just the parts of the format. ;; `time-stamp-string-preprocess' is the full-fledged parser normally ;; 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 @@ ,@body))) (defmacro with-time-stamp-test-time (reference-time &rest body) - "Force any contained time-stamp call to use time REFERENCE-TIME." + "Force `time-stamp' to use time REFERENCE-TIME while evaluating BODY." (declare (indent 1) (debug t)) `(cl-letf* ((orig-time-stamp-string-fn (symbol-function 'time-stamp-string)) @@ -55,14 +55,14 @@ ,@body)) (defmacro with-time-stamp-system-name (name &rest body) - "Force (system-name) to return NAME while evaluating BODY." + "Force `system-name' to return NAME while evaluating BODY." (declare (indent 1) (debug t)) `(cl-letf (((symbol-function 'system-name) (lambda () ,name))) ,@body)) (defmacro time-stamp-should-warn (form) - "Similar to `should' but verifies that a format warning is generated." + "Similar to `should' and also verify that FORM generates a format warning." (declare (debug t)) `(let ((warning-count 0)) (cl-letf (((symbol-function 'time-stamp-conv-warn) @@ -269,70 +269,111 @@ (ert-deftest time-stamp-format-day-of-week () "Test time-stamp formats for named day of week." (with-time-stamp-test-env - (let ((Mon (format-time-string "%a" ref-time1 t)) - (MON (format-time-string "%^a" ref-time1 t)) - (Monday (format-time-string "%A" ref-time1 t)) - (MONDAY (format-time-string "%^A" ref-time1 t))) - ;; implemented and documented since 1997 - (should (equal (time-stamp-string "%3a" ref-time1) Mon)) + (let* ((Mon (format-time-string "%a" ref-time1 t)) + (MON (format-time-string "%^a" ref-time1 t)) + (Monday (format-time-string "%A" ref-time1 t)) + (MONDAY (format-time-string "%^A" ref-time1 t)) + (p4-Mon (string-pad Mon 4 ?\s t)) + (p4-MON (string-pad MON 4 ?\s t)) + (p10-Monday (string-pad Monday 10 ?\s t)) + (p10-MONDAY (string-pad MONDAY 10 ?\s t))) + ;; implemented and recommended since 1997 (should (equal (time-stamp-string "%#A" ref-time1) MONDAY)) - ;; documented 1997-2019 - (should (equal (time-stamp-string "%3A" ref-time1) - (substring MONDAY 0 3))) + (should (equal (time-stamp-string "%#10A" ref-time1) p10-MONDAY)) + ;; implemented since 1997, recommended 1997-2024 + (should (equal (time-stamp-string "%3a" ref-time1) Mon)) + ;; recommended 1997-2019 (should (equal (time-stamp-string "%:a" ref-time1) Monday)) - ;; implemented since 2001, documented since 2019 + ;; recommended 1997-2019, warned since 2024, will change + (time-stamp-should-warn + (should (equal (time-stamp-string "%3A" ref-time1) MON))) + (time-stamp-should-warn + (should (equal (time-stamp-string "%10A" ref-time1) p10-MONDAY))) + ;; implemented since 2001, recommended since 2019 (should (equal (time-stamp-string "%#a" ref-time1) MON)) + (should (equal (time-stamp-string "%#3a" ref-time1) MON)) + (should (equal (time-stamp-string "%#4a" ref-time1) p4-MON)) + ;; implemented since 2001, recommended 2019-2024 (should (equal (time-stamp-string "%:A" ref-time1) Monday)) - ;; allowed but undocumented since 2019 (warned 1997-2019) + ;; broken 2019-2024 + (should (equal (time-stamp-string "%:10A" ref-time1) p10-Monday)) + ;; broken in 2019, changed in 2024 + (should (equal (time-stamp-string "%-A" ref-time1) Monday)) + (should (equal (time-stamp-string "%_A" ref-time1) Monday)) + ;; allowed but not recommended since 2019 (warned 1997-2019) (should (equal (time-stamp-string "%^A" ref-time1) MONDAY)) - ;; warned 1997-2019, changed in 2019 + ;; warned 1997-2019, changed in 2019, recommended (with caveat) since 2024 (should (equal (time-stamp-string "%a" ref-time1) Mon)) + (should (equal (time-stamp-string "%4a" ref-time1) p4-Mon)) + (should (equal (time-stamp-string "%04a" ref-time1) p4-Mon)) + (should (equal (time-stamp-string "%A" ref-time1) Monday)) + ;; warned 1997-2019, changed in 2019 (should (equal (time-stamp-string "%^a" ref-time1) MON)) - (should (equal (time-stamp-string "%A" ref-time1) Monday))))) + (should (equal (time-stamp-string "%^4a" ref-time1) p4-MON))))) (ert-deftest time-stamp-format-month-name () "Test time-stamp formats for month name." (with-time-stamp-test-env - (let ((Jan (format-time-string "%b" ref-time1 t)) - (JAN (format-time-string "%^b" ref-time1 t)) - (January (format-time-string "%B" ref-time1 t)) - (JANUARY (format-time-string "%^B" ref-time1 t))) - ;; implemented and documented since 1997 - (should (equal (time-stamp-string "%3b" ref-time1) - (substring January 0 3))) + (let* ((Jan (format-time-string "%b" ref-time1 t)) + (JAN (format-time-string "%^b" ref-time1 t)) + (January (format-time-string "%B" ref-time1 t)) + (JANUARY (format-time-string "%^B" ref-time1 t)) + (p4-Jan (string-pad Jan 4 ?\s t)) + (p4-JAN (string-pad JAN 4 ?\s t)) + (p10-January (string-pad January 10 ?\s t)) + (p10-JANUARY (string-pad JANUARY 10 ?\s t))) + ;; implemented and recommended since 1997 (should (equal (time-stamp-string "%#B" ref-time1) JANUARY)) - ;; documented 1997-2019 - (should (equal (time-stamp-string "%3B" ref-time1) - (substring JANUARY 0 3))) + (should (equal (time-stamp-string "%#10B" ref-time1) p10-JANUARY)) + ;; implemented since 1997, recommended 1997-2024 + (should (equal (time-stamp-string "%3b" ref-time1) Jan)) + ;; recommended 1997-2019 (should (equal (time-stamp-string "%:b" ref-time1) January)) - ;; implemented since 2001, documented since 2019 + ;; recommended 1997-2019, warned since 2024, will change + (time-stamp-should-warn + (should (equal (time-stamp-string "%3B" ref-time1) JAN))) + (time-stamp-should-warn + (should (equal (time-stamp-string "%10B" ref-time1) p10-JANUARY))) + ;; implemented since 2001, recommended since 2019 (should (equal (time-stamp-string "%#b" ref-time1) JAN)) + (should (equal (time-stamp-string "%#3b" ref-time1) JAN)) + (should (equal (time-stamp-string "%#4b" ref-time1) p4-JAN)) + ;; implemented since 2001, recommended 2019-2024 (should (equal (time-stamp-string "%:B" ref-time1) January)) - ;; allowed but undocumented since 2019 (warned 1997-2019) + ;; broken 2019-2024 + (should (equal (time-stamp-string "%:10B" ref-time1) p10-January)) + ;; broken in 2019, changed in 2024 + (should (equal (time-stamp-string "%-B" ref-time1) January)) + (should (equal (time-stamp-string "%_B" ref-time1) January)) + ;; allowed but not recommended since 2019 (warned 1997-2019) (should (equal (time-stamp-string "%^B" ref-time1) JANUARY)) - ;; warned 1997-2019, changed in 2019 + ;; warned 1997-2019, changed in 2019, recommended (with caveat) since 2024 (should (equal (time-stamp-string "%b" ref-time1) Jan)) + (should (equal (time-stamp-string "%4b" ref-time1) p4-Jan)) + (should (equal (time-stamp-string "%04b" ref-time1) p4-Jan)) + (should (equal (time-stamp-string "%B" ref-time1) January)) + ;; warned 1997-2019, changed in 2019 (should (equal (time-stamp-string "%^b" ref-time1) JAN)) - (should (equal (time-stamp-string "%B" ref-time1) January))))) + (should (equal (time-stamp-string "%^4b" ref-time1) p4-JAN))))) (ert-deftest time-stamp-format-day-of-month () "Test time-stamp formats for day of month." (with-time-stamp-test-env - ;; implemented and documented since 1995 + ;; implemented since 1995, recommended until 2024 (should (equal (time-stamp-string "%2d" ref-time1) " 2")) (should (equal (time-stamp-string "%2d" ref-time2) "18")) (should (equal (time-stamp-string "%02d" ref-time1) "02")) (should (equal (time-stamp-string "%02d" ref-time2) "18")) - ;; documented 1997-2019 + ;; recommended 1997-2019 (should (equal (time-stamp-string "%:d" ref-time1) "2")) (should (equal (time-stamp-string "%:d" ref-time2) "18")) - ;; implemented since 1997, documented since 2019 + ;; implemented since 1997, recommended 2019-2024 (should (equal (time-stamp-string "%1d" ref-time1) "2")) (should (equal (time-stamp-string "%1d" ref-time2) "18")) - ;; allowed but undocumented since 2019 (warned 1997-2019) + ;; warned 1997-2019, allowed 2019, recommended (with caveat) since 2024 (should (equal (time-stamp-string "%-d" ref-time1) "2")) (should (equal (time-stamp-string "%-d" ref-time2) "18")) - ;; warned 1997-2019, changed in 2019 + ;; warned 1997-2019, changed in 2019, recommended (with caveat) since 2024 (should (equal (time-stamp-string "%_d" ref-time1) " 2")) (should (equal (time-stamp-string "%_d" ref-time2) "18")) (should (equal (time-stamp-string "%d" ref-time1) "02")) @@ -341,26 +382,26 @@ (ert-deftest time-stamp-format-hours-24 () "Test time-stamp formats for hour on a 24-hour clock." (with-time-stamp-test-env - ;; implemented and documented since 1995 + ;; implemented since 1995, recommended until 2024 (should (equal (time-stamp-string "%2H" ref-time1) "15")) (should (equal (time-stamp-string "%2H" ref-time2) "12")) (should (equal (time-stamp-string "%2H" ref-time3) " 6")) (should (equal (time-stamp-string "%02H" ref-time1) "15")) (should (equal (time-stamp-string "%02H" ref-time2) "12")) (should (equal (time-stamp-string "%02H" ref-time3) "06")) - ;; documented 1997-2019 + ;; recommended 1997-2019 (should (equal (time-stamp-string "%:H" ref-time1) "15")) (should (equal (time-stamp-string "%:H" ref-time2) "12")) (should (equal (time-stamp-string "%:H" ref-time3) "6")) - ;; implemented since 1997, documented since 2019 + ;; implemented since 1997, recommended 2019-2024 (should (equal (time-stamp-string "%1H" ref-time1) "15")) (should (equal (time-stamp-string "%1H" ref-time2) "12")) (should (equal (time-stamp-string "%1H" ref-time3) "6")) - ;; allowed but undocumented since 2019 (warned 1997-2019) + ;; warned 1997-2019, allowed 2019, recommended (with caveat) since 2024 (should (equal (time-stamp-string "%-H" ref-time1) "15")) (should (equal (time-stamp-string "%-H" ref-time2) "12")) (should (equal (time-stamp-string "%-H" ref-time3) "6")) - ;; warned 1997-2019, changed in 2019 + ;; warned 1997-2019, changed in 2019, recommended (with caveat) since 2024 (should (equal (time-stamp-string "%_H" ref-time1) "15")) (should (equal (time-stamp-string "%_H" ref-time2) "12")) (should (equal (time-stamp-string "%_H" ref-time3) " 6")) @@ -371,26 +412,26 @@ (ert-deftest time-stamp-format-hours-12 () "Test time-stamp formats for hour on a 12-hour clock." (with-time-stamp-test-env - ;; implemented and documented since 1995 + ;; implemented since 1995, recommended until 2024 (should (equal (time-stamp-string "%2I" ref-time1) " 3")) (should (equal (time-stamp-string "%2I" ref-time2) "12")) (should (equal (time-stamp-string "%2I" ref-time3) " 6")) (should (equal (time-stamp-string "%02I" ref-time1) "03")) (should (equal (time-stamp-string "%02I" ref-time2) "12")) (should (equal (time-stamp-string "%02I" ref-time3) "06")) - ;; documented 1997-2019 + ;; recommended 1997-2019 (should (equal (time-stamp-string "%:I" ref-time1) "3")) ;PM (should (equal (time-stamp-string "%:I" ref-time2) "12")) ;PM (should (equal (time-stamp-string "%:I" ref-time3) "6")) ;AM - ;; implemented since 1997, documented since 2019 + ;; implemented since 1997, recommended since 2019 (should (equal (time-stamp-string "%1I" ref-time1) "3")) (should (equal (time-stamp-string "%1I" ref-time2) "12")) (should (equal (time-stamp-string "%1I" ref-time3) "6")) - ;; allowed but undocumented since 2019 (warned 1997-2019) + ;; warned 1997-2019, allowed 2019, recommended (with caveat) since 2024 (should (equal (time-stamp-string "%-I" ref-time1) "3")) (should (equal (time-stamp-string "%-I" ref-time2) "12")) (should (equal (time-stamp-string "%-I" ref-time3) "6")) - ;; warned 1997-2019, changed in 2019 + ;; warned 1997-2019, changed in 2019, recommended (with caveat) since 2024 (should (equal (time-stamp-string "%_I" ref-time1) " 3")) (should (equal (time-stamp-string "%_I" ref-time2) "12")) (should (equal (time-stamp-string "%_I" ref-time3) " 6")) @@ -401,21 +442,21 @@ (ert-deftest time-stamp-format-month-number () "Test time-stamp formats for month number." (with-time-stamp-test-env - ;; implemented and documented since 1995 + ;; implemented since 1995, recommended until 2024 (should (equal (time-stamp-string "%2m" ref-time1) " 1")) (should (equal (time-stamp-string "%2m" ref-time2) "11")) (should (equal (time-stamp-string "%02m" ref-time1) "01")) (should (equal (time-stamp-string "%02m" ref-time2) "11")) - ;; documented 1997-2019 + ;; recommended 1997-2019 (should (equal (time-stamp-string "%:m" ref-time1) "1")) (should (equal (time-stamp-string "%:m" ref-time2) "11")) - ;; implemented since 1997, documented since 2019 + ;; implemented since 1997, recommended since 2019 (should (equal (time-stamp-string "%1m" ref-time1) "1")) (should (equal (time-stamp-string "%1m" ref-time2) "11")) - ;; allowed but undocumented since 2019 (warned 1997-2019) + ;; warned 1997-2019, allowed 2019, recommended (with caveat) since 2024 (should (equal (time-stamp-string "%-m" ref-time1) "1")) (should (equal (time-stamp-string "%-m" ref-time2) "11")) - ;; warned 1997-2019, changed in 2019 + ;; warned 1997-2019, changed in 2019, recommended (with caveat) since 2024 (should (equal (time-stamp-string "%_m" ref-time1) " 1")) (should (equal (time-stamp-string "%_m" ref-time2) "11")) (should (equal (time-stamp-string "%m" ref-time1) "01")) @@ -424,21 +465,21 @@ (ert-deftest time-stamp-format-minute () "Test time-stamp formats for minute." (with-time-stamp-test-env - ;; implemented and documented since 1995 + ;; implemented since 1995, recommended until 2024 (should (equal (time-stamp-string "%2M" ref-time1) " 4")) (should (equal (time-stamp-string "%2M" ref-time2) "14")) (should (equal (time-stamp-string "%02M" ref-time1) "04")) (should (equal (time-stamp-string "%02M" ref-time2) "14")) - ;; documented 1997-2019 + ;; recommended 1997-2019 (should (equal (time-stamp-string "%:M" ref-time1) "4")) (should (equal (time-stamp-string "%:M" ref-time2) "14")) - ;; implemented since 1997, documented since 2019 + ;; implemented since 1997, recommended since 2019 (should (equal (time-stamp-string "%1M" ref-time1) "4")) (should (equal (time-stamp-string "%1M" ref-time2) "14")) - ;; allowed but undocumented since 2019 (warned 1997-2019) + ;; warned 1997-2019, allowed 2019, recommended (with caveat) since 2024 (should (equal (time-stamp-string "%-M" ref-time1) "4")) (should (equal (time-stamp-string "%-M" ref-time2) "14")) - ;; warned 1997-2019, changed in 2019 + ;; warned 1997-2019, changed in 2019, recommended (with caveat) since 2024 (should (equal (time-stamp-string "%_M" ref-time1) " 4")) (should (equal (time-stamp-string "%_M" ref-time2) "14")) (should (equal (time-stamp-string "%M" ref-time1) "04")) @@ -447,21 +488,21 @@ (ert-deftest time-stamp-format-second () "Test time-stamp formats for second." (with-time-stamp-test-env - ;; implemented and documented since 1995 + ;; implemented since 1995, recommended until 2024 (should (equal (time-stamp-string "%2S" ref-time1) " 5")) (should (equal (time-stamp-string "%2S" ref-time2) "15")) (should (equal (time-stamp-string "%02S" ref-time1) "05")) (should (equal (time-stamp-string "%02S" ref-time2) "15")) - ;; documented 1997-2019 + ;; recommended 1997-2019 (should (equal (time-stamp-string "%:S" ref-time1) "5")) (should (equal (time-stamp-string "%:S" ref-time2) "15")) - ;; implemented since 1997, documented since 2019 + ;; implemented since 1997, recommended since 2019 (should (equal (time-stamp-string "%1S" ref-time1) "5")) (should (equal (time-stamp-string "%1S" ref-time2) "15")) - ;; allowed but undocumented since 2019 (warned 1997-2019) + ;; warned 1997-2019, allowed 2019, recommended (with caveat) since 2024 (should (equal (time-stamp-string "%-S" ref-time1) "5")) (should (equal (time-stamp-string "%-S" ref-time2) "15")) - ;; warned 1997-2019, changed in 2019 + ;; warned 1997-2019, changed in 2019, recommended (with caveat) since 2024 (should (equal (time-stamp-string "%_S" ref-time1) " 5")) (should (equal (time-stamp-string "%_S" ref-time2) "15")) (should (equal (time-stamp-string "%S" ref-time1) "05")) @@ -470,12 +511,14 @@ (ert-deftest time-stamp-format-year-2digit () "Test time-stamp formats for %y." (with-time-stamp-test-env - ;; implemented and documented since 1995 + ;; implemented since 1995, recommended 1995-2024 (should (equal (time-stamp-string "%02y" ref-time1) "06")) (should (equal (time-stamp-string "%02y" ref-time2) "16")) - ;; documented 1997-2019 - (should (equal (time-stamp-string "%:y" ref-time1) "2006")) - (should (equal (time-stamp-string "%:y" ref-time2) "2016")) + ;; recommended 1997-2019, warned since 2024 + (time-stamp-should-warn + (should (equal (time-stamp-string "%:y" ref-time1) "2006"))) + (time-stamp-should-warn + (should (equal (time-stamp-string "%:y" ref-time2) "2016"))) ;; warned 1997-2019, changed in 2019 ;; (We don't expect the %-y or %_y form to be useful, ;; but we test both so that we can confidently state that @@ -484,6 +527,7 @@ (should (equal (time-stamp-string "%-y" ref-time2) "16")) (should (equal (time-stamp-string "%_y" ref-time1) " 6")) (should (equal (time-stamp-string "%_y" ref-time2) "16")) + ;; warned 1997-2019, changed in 2019, recommended (with caveat) since 2024 (should (equal (time-stamp-string "%y" ref-time1) "06")) (should (equal (time-stamp-string "%y" ref-time2) "16")) ;; implemented since 1995, warned since 2019, will change @@ -495,7 +539,7 @@ (ert-deftest time-stamp-format-year-4digit () "Test time-stamp format %Y." (with-time-stamp-test-env - ;; implemented since 1997, documented since 2019 + ;; implemented since 1997, recommended since 2019 (should (equal (time-stamp-string "%Y" ref-time1) "2006")) ;; numbers do not truncate (should (equal (time-stamp-string "%2Y" ref-time1) "2006")) @@ -510,15 +554,16 @@ (Am (format-time-string "%p" ref-time3 t)) (PM (format-time-string "%^p" ref-time1 t)) (AM (format-time-string "%^p" ref-time3 t))) - ;; implemented and documented since 1997 + ;; implemented and recommended since 1997 (should (equal (time-stamp-string "%#p" ref-time1) pm)) (should (equal (time-stamp-string "%#p" ref-time3) am)) + ;; implemented since 1997, recommended 1997-2024 (should (equal (time-stamp-string "%P" ref-time1) Pm)) (should (equal (time-stamp-string "%P" ref-time3) Am)) ;; implemented since 1997 (should (equal (time-stamp-string "%^#p" ref-time1) pm)) (should (equal (time-stamp-string "%^#p" ref-time3) am)) - ;; warned 1997-2019, changed in 2019 + ;; warned 1997-2019, changed in 2019, recommended (with caveat) since 2024 (should (equal (time-stamp-string "%p" ref-time1) Pm)) (should (equal (time-stamp-string "%p" ref-time3) Am)) ;; changed in 2024 @@ -543,19 +588,22 @@ (with-time-stamp-test-env (let ((UTC-abbr (format-time-string "%Z" ref-time1 t)) (utc-abbr (format-time-string "%#Z" ref-time1 t))) - ;; implemented and documented since 1995 + ;; implemented and recommended since 1995 (should (equal (time-stamp-string "%Z" ref-time1) UTC-abbr)) - ;; implemented since 1997, documented since 2019 - (should (equal (time-stamp-string "%#Z" ref-time1) utc-abbr))))) + ;; implemented since 1997, recommended since 2019 + (should (equal (time-stamp-string "%#Z" ref-time1) utc-abbr)) + ;; ^ accepted and ignored since 1995/1997, test for consistency with %p + (should (equal (time-stamp-string "%^Z" ref-time1) UTC-abbr)) + (should (equal (time-stamp-string "%^#Z" ref-time1) utc-abbr))))) (ert-deftest time-stamp-format-time-zone-offset () "Test time-stamp legacy format %z and spot-test new offset format %5z." (with-time-stamp-test-env (let ((utc-abbr (format-time-string "%#Z" ref-time1 t))) - ;; documented 1995-2019, warned since 2019, will change + ;; recommended 1995-2019, warned since 2019, will change (time-stamp-should-warn (equal (time-stamp-string "%z" ref-time1) utc-abbr))) - ;; implemented and documented (with compat caveat) since 2019 + ;; implemented and recommended (with compat caveat) since 2019 (should (equal (time-stamp-string "%5z" ref-time1) "+0000")) (let ((time-stamp-time-zone "PST8")) (should (equal (time-stamp-string "%5z" ref-time1) "-0800"))) @@ -563,20 +611,21 @@ (should (equal (time-stamp-string "%5z" ref-time1) "-1000"))) (let ((time-stamp-time-zone "CET-1")) (should (equal (time-stamp-string "%5z" ref-time1) "+0100"))) - ;; implemented since 2019, verify that these don't warn + ;; implemented since 2019, recommended (with compat caveat) since 2024 ;; See also the "formatz" tests below, which since 2021 test more ;; variants with more offsets. (should (equal (time-stamp-string "%-z" ref-time1) "+00")) + (should (equal (time-stamp-string "%:::z" ref-time1) "+00")) (should (equal (time-stamp-string "%:z" ref-time1) "+00:00")) + ;; implemented since 2019 (should (equal (time-stamp-string "%::z" ref-time1) "+00:00:00")) - (should (equal (time-stamp-string "%9::z" ref-time1) "+00:00:00")) - (should (equal (time-stamp-string "%:::z" ref-time1) "+00")))) + (should (equal (time-stamp-string "%9::z" ref-time1) "+00:00:00")))) (ert-deftest time-stamp-format-non-date-conversions () "Test time-stamp formats for non-date items." (with-time-stamp-test-env (with-time-stamp-system-name "test-system-name.example.org" - ;; implemented and documented since 1995 + ;; implemented and recommended since 1995 (should (equal (time-stamp-string "%%" ref-time1) "%")) ;% last char (should (equal (time-stamp-string "%%P" ref-time1) "%P")) ;% not last char (should (equal (time-stamp-string "%f" ref-time1) "time-stamped-file")) @@ -589,15 +638,18 @@ (let ((mail-host-address nil)) (should (equal (time-stamp-string "%h" ref-time1) "test-system-name.example.org"))) - ;; documented 1995-2019 - (should (equal (time-stamp-string "%s" ref-time1) - "test-system-name.example.org")) - (should (equal (time-stamp-string "%U" ref-time1) "100%d Tester")) - (should (equal (time-stamp-string "%u" ref-time1) "test-logname")) - ;; implemented since 2001, documented since 2019 + ;; recommended 1997-2019, warned since 2024 + (time-stamp-should-warn + (should (equal (time-stamp-string "%s" ref-time1) + "test-system-name.example.org"))) + (time-stamp-should-warn + (should (equal (time-stamp-string "%U" ref-time1) "100%d Tester"))) + (time-stamp-should-warn + (should (equal (time-stamp-string "%u" ref-time1) "test-logname"))) + ;; implemented since 2001, recommended since 2019 (should (equal (time-stamp-string "%L" ref-time1) "100%d Tester")) (should (equal (time-stamp-string "%l" ref-time1) "test-logname")) - ;; implemented since 2007, documented since 2019 + ;; implemented since 2007, recommended since 2019 (should (equal (time-stamp-string "%Q" ref-time1) "test-system-name.example.org")) (should (equal (time-stamp-string "%q" ref-time1) "test-system-name"))) @@ -668,24 +720,20 @@ (ert-deftest time-stamp-format-string-width () "Test time-stamp string width modifiers." (with-time-stamp-test-env - (let ((May (format-time-string "%b" ref-time3 t)) - (SUN (format-time-string "%^a" ref-time3 t)) - (NOV (format-time-string "%^b" ref-time2 t))) - ;; strings truncate on the right or are blank-padded on the left - (should (equal (time-stamp-string "%0b" ref-time3) "")) - (should (equal (time-stamp-string "%1b" ref-time3) (substring May 0 1))) - (should (equal (time-stamp-string "%2b" ref-time3) (substring May 0 2))) - (should (equal (time-stamp-string "%3b" ref-time3) (substring May 0 3))) - (should (equal (time-stamp-string "%4b" ref-time3) (concat " " May))) - (should (equal (time-stamp-string "%0%" ref-time3) "")) - (should (equal (time-stamp-string "%1%" ref-time3) "%")) - (should (equal (time-stamp-string "%2%" ref-time3) " %")) - (should (equal (time-stamp-string "%9%" ref-time3) " %")) - (should (equal (time-stamp-string "%10%" ref-time3) " %")) - (should (equal (time-stamp-string "%#3a" ref-time3) - (substring SUN 0 3))) - (should (equal (time-stamp-string "%#3b" ref-time2) - (substring NOV 0 3)))))) + (let ((UTC-abbr (format-time-string "%Z" ref-time1 t))) + (should (equal (time-stamp-string "%1%" ref-time3) "%")) + (should (equal (time-stamp-string "%2%" ref-time3) " %")) + (should (equal (time-stamp-string "%9%" ref-time3) " %")) + (should (equal (time-stamp-string "%10%" ref-time3) " %")) + (should (equal (time-stamp-string "%03d" ref-time3) "025")) + (should (equal (time-stamp-string "%3d" ref-time3) " 25")) + (should (equal (time-stamp-string "%_3d" ref-time3) " 25")) + ;; since 2024 + (should (equal (time-stamp-string "%0d" ref-time1) "02")) + (should (equal (time-stamp-string "%0d" ref-time2) "18")) + ;; broken 2019-2024 + (should (equal (time-stamp-string "%-Z" ref-time1) UTC-abbr)) + (should (equal (time-stamp-string "%_Z" ref-time1) UTC-abbr))))) ;;; Tests of helper functions @@ -895,11 +943,11 @@ The functions in `pattern-mod' are composed left to right." (defun formatz-mod-pad-r10 (string) "Return STRING padded on the right to 10 characters." - (concat string (make-string (- 10 (length string)) ?\s))) + (string-pad string 10)) (defun formatz-mod-pad-r12 (string) "Return STRING padded on the right to 12 characters." - (concat string (make-string (- 12 (length string)) ?\s))) + (string-pad string 12)) ;; Convenience macro for generating groups of test cases. @@ -966,7 +1014,7 @@ the other expected results for hours greater than 99 with non-zero seconds." ;;;; The actual test cases for %z -;;; %z formats without colons. +;;; Test %z formats without colons. ;; Option character "-" (minus) minimizes; it removes "00" minutes. (formatz-generate-tests ("%-z" "%-3z") @@ -976,7 +1024,7 @@ the other expected results for hours greater than 99 with non-zero seconds." ("+100:00") ("+100:00:30")) -;; Tests that minus with padding pads with spaces. +;; Minus with padding pads with spaces. (formatz-generate-tests ("%-12z") ("+00 " formatz-mod-pad-r12) ("+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." ("+100:00 " formatz-mod-pad-r12) ("+100:00:30 " formatz-mod-pad-r12)) -;; Tests that 0 after other digits becomes padding of ten, not zero flag. +;; 0 after other digits becomes padding of ten, not zero flag. (formatz-generate-tests ("%-10z") ("+00 " formatz-mod-pad-r10) ("+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." ("+100:00") ("+100:00:30")) -;; Tests that padding adds spaces. +;; Padding adds spaces. (formatz-generate-tests ("%12z") ("+0000 " formatz-mod-add-00 formatz-mod-pad-r12) ("+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." ("+100:00:00 " formatz-mod-add-colon00 formatz-mod-pad-r12) ("+100:00:30 " formatz-mod-pad-r12)) -;;; %z formats with colons +;;; Test %z formats with colons. ;; Three colons can output hours only, ;; 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." ("+100:00") ("+100:00:30")) -;; Padding with three colons adds spaces +;; Padding with three colons adds spaces. (formatz-generate-tests ("%12:::z") ("+00 " formatz-mod-pad-r12) ("+00:30 " formatz-mod-pad-r12) ("+00:00:30 " formatz-mod-pad-r12) ("+100:00 " formatz-mod-pad-r12) ("+100:00:30 " formatz-mod-pad-r12)) -;; Tests that 0 after other digits becomes padding of ten, not zero flag. + +;; 0 after other digits becomes padding of ten, not zero flag. (formatz-generate-tests ("%10:::z") ("+00 " formatz-mod-pad-r10) ("+00:30 " formatz-mod-pad-r10) @@ -1084,7 +1133,7 @@ the other expected results for hours greater than 99 with non-zero seconds." ("+100:00") ("+100:00:30")) -;; Padding with one colon adds spaces +;; Padding with one colon adds spaces. (formatz-generate-tests ("%12:z") ("+00:00 " formatz-mod-add-colon00 formatz-mod-pad-r12) ("+00:30 " formatz-mod-pad-r12) @@ -1117,7 +1166,7 @@ the other expected results for hours greater than 99 with non-zero seconds." ("+100:00:00 " formatz-mod-add-colon00 formatz-mod-pad-r12) ("+100:00:30 " formatz-mod-pad-r12)) -;;; Illegal %z formats +;;; Test illegal %z formats. (ert-deftest formatz-illegal-options () "Test that illegal/nonsensical/ambiguous %z formats don't produce output."