diff --git a/lisp/time-stamp.el b/lisp/time-stamp.el index 8c28920d219..1b95396e744 100644 --- a/lisp/time-stamp.el +++ b/lisp/time-stamp.el @@ -5,8 +5,8 @@ ;; This file is part of GNU Emacs. -;; Maintainer: Stephen Gildea -;; Keywords: tools +;; Author: Stephen Gildea +;; Keywords: files, tools ;; GNU Emacs is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by @@ -25,20 +25,19 @@ ;; A template in a file can be updated with a new time stamp when ;; you save the file. For example: -;; static char *ts = "sdmain.c Time-stamp: <2020-04-18 14:10:21 gildea>"; +;; static char *ts = "sdmain.c Time-stamp: <2024-04-18 14:10:21 gildea>"; ;; To use time-stamping, add this line to your init file: ;; (add-hook 'before-save-hook 'time-stamp) ;; Now any time-stamp templates in your files will be updated automatically. -;; See the documentation for the functions `time-stamp' -;; and `time-stamp-toggle-active' for details. +;; See the documentation for the function `time-stamp' for details. ;;; Code: (defgroup time-stamp nil "Maintain last change time stamps in files edited by Emacs." - :group 'data + :group 'files :group 'extensions) @@ -47,34 +46,34 @@ 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 -%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) +%: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 +%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) 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 -%h mail host name +%% 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 +%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. -For example, to get the format used by the `date' command, +For example, to get a common format used by the `date' command, use \"%3a %3b %2d %02H:%02M:%02S %Z %Y\". The values of non-numeric formatted items depend on the locale @@ -266,20 +265,22 @@ If you were to change `time-stamp-pattern', `time-stamp-line-limit', `time-stamp-start', or `time-stamp-end' in your init file, you would be incompatible with other people's files. -See also `time-stamp-count' and `time-stamp-inserts-lines'. - Examples: -\"-10/\" (sets only `time-stamp-line-limit') +;; time-stamp-pattern: \"-10/\" + (sets only `time-stamp-line-limit') -\"-9/^Last modified: %%$\" (sets `time-stamp-line-limit', -`time-stamp-start' and `time-stamp-end') +// time-stamp-pattern: \"-9/^Last modified: %%$\" + (sets `time-stamp-line-limit', `time-stamp-start' and `time-stamp-end') -\"@set Time-stamp: %:B %1d, %Y$\" (sets `time-stamp-start', -`time-stamp-format' and `time-stamp-end') +@c time-stamp-pattern: \"@set Time-stamp: %:B %1d, %Y$\" + (sets `time-stamp-start', `time-stamp-format' and `time-stamp-end') -\"newcommand{\\\\\\\\timestamp}{%%}\" (sets `time-stamp-start' -and `time-stamp-end')") +%% time-stamp-pattern: \"newcommand{\\\\\\\\timestamp}{%%}\" + (sets `time-stamp-start'and `time-stamp-end') + + +See also `time-stamp-count' and `time-stamp-inserts-lines'.") ;;;###autoload(put 'time-stamp-pattern 'safe-local-variable 'stringp) @@ -287,8 +288,8 @@ and `time-stamp-end')") ;;;###autoload (defun time-stamp () "Update any time stamp string(s) in the buffer. -This function looks for a time stamp template and updates it with -the current date, time, and/or other info. +Look for a time stamp template and update it with the current date, +time, and/or other info. The template, which you manually create on one of the first 8 lines of the file before running this function, by default can look like @@ -297,7 +298,7 @@ one of the following (your choice): Time-stamp: \" \" This function writes the current time between the brackets or quotes, by default formatted like this: - Time-stamp: <2020-08-07 17:10:21 gildea> + Time-stamp: <2024-08-07 17:10:21 gildea> Although you can run this function manually to update a time stamp once, usually you want automatic time stamp updating. @@ -311,7 +312,7 @@ To enable automatic time-stamping for only a specific file, add this line to a local variables list near the end of the file: eval: (add-hook \\='before-save-hook \\='time-stamp nil t) -If the file has no time-stamp template, this function does nothing. +If the file has no time stamp template, this function does nothing. You can set `time-stamp-pattern' in a file's local variables list to customize the information in the time stamp and where it is written. @@ -419,7 +420,7 @@ Returns the end point, which is where `time-stamp' begins the next search." (cond ((not time-stamp-active) (if time-stamp-warn-inactive - ;; don't signal an error in a write-file-hook + ;; don't signal an error in a hook (progn (message "Warning: time-stamp-active is off; did not time-stamp buffer.") (sit-for 1)))) @@ -801,6 +802,8 @@ Suggests replacing OLD-FORM with NEW-FORM." ;; - The %_z format always outputs seconds, allowing all added padding ;; to be spaces. Without this rule, there would be no way to ;; request seconds that worked for both 2- and 3-digit hours. +;; (We consider 3-digit hours not because such offsets are in use but +;; instead to guide our design toward consistency and extensibility.) ;; - Conflicting options are rejected, lest users depend ;; on incidental behavior. ;; @@ -843,7 +846,7 @@ Suggests replacing OLD-FORM with NEW-FORM." colon-count field-width offset-secs) - "Formats a time offset according to a %z variation. + "Format a time offset according to a %z variation. With no flags, the output includes hours and minutes: +-HHMM unless there is a non-zero seconds part, in which case the seconds diff --git a/test/lisp/time-stamp-tests.el b/test/lisp/time-stamp-tests.el index a4c30d64225..36889257724 100644 --- a/test/lisp/time-stamp-tests.el +++ b/test/lisp/time-stamp-tests.el @@ -535,7 +535,7 @@ (should (equal (time-stamp-string "%#Z" ref-time1) utc-abbr))))) (ert-deftest time-stamp-format-time-zone-offset () - "Tests time-stamp legacy format %z and spot tests of new offset format %5z." + "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 @@ -617,7 +617,7 @@ (should (equal (time-stamp-string "No percent" ref-time1) "No percent")))) (ert-deftest time-stamp-format-multiple-conversions () - "Tests that multiple %-conversions are independent." + "Test that multiple %-conversions are independent." (with-time-stamp-test-env (let ((Mon (format-time-string "%a" ref-time1 t)) (MON (format-time-string "%^a" ref-time1 t)) @@ -719,7 +719,7 @@ ;;;; Setup for tests of time offset formatting with %z (defun formatz (format zone) - "Uses FORMAT to format the offset of ZONE, returning the result. + "Use FORMAT to format the offset of ZONE, returning the result. FORMAT must be time format \"%z\" or some variation thereof. ZONE is as the ZONE argument of the `format-time-string' function. This function is called by 99% of the `time-stamp' \"%z\" unit tests." @@ -733,7 +733,7 @@ This function is called by 99% of the `time-stamp' \"%z\" unit tests." ))) (defun format-time-offset (format offset-secs) - "Uses FORMAT to format the time zone represented by OFFSET-SECS. + "Use FORMAT to format the time zone represented by OFFSET-SECS. FORMAT must be time format \"%z\" or some variation thereof. This function is a wrapper around `time-stamp-formatz-from-parsed-options' and is called by some low-level `time-stamp' \"%z\" unit tests." @@ -765,20 +765,20 @@ and is called by some low-level `time-stamp' \"%z\" unit tests." trailing-string))) (defun fz-make+zone (h &optional m s) - "Creates a non-negative offset." + "Create a non-negative offset." (declare (pure t)) (let ((m (or m 0)) (s (or s 0))) (+ (* 3600 h) (* 60 m) s))) (defun fz-make-zone (h &optional m s) - "Creates a negative offset. The arguments are all non-negative." + "Create a negative offset. The arguments are all non-negative." (declare (pure t)) (- (fz-make+zone h m s))) (defmacro formatz-should-equal (zone expect) - "Formats ZONE and compares it to EXPECT. -Uses the free variables `form-string' and `pattern-mod'. + "Format ZONE and compares it to EXPECT. +Use the free variables `form-string' and `pattern-mod'. The functions in `pattern-mod' are composed left to right." (declare (debug t)) `(let ((result ,expect)) @@ -790,7 +790,7 @@ The functions in `pattern-mod' are composed left to right." ;; for hours, minutes, and seconds. (defun formatz-hours-exact-helper (form-string pattern-mod) - "Tests format %z with whole hours." + "Test format %z with whole hours." (formatz-should-equal (fz-make+zone 0) "+00") ;0 sign always +, both digits (formatz-should-equal (fz-make+zone 10) "+10") (formatz-should-equal (fz-make-zone 10) "-10") @@ -801,7 +801,7 @@ The functions in `pattern-mod' are composed left to right." ) (defun formatz-nonzero-minutes-helper (form-string pattern-mod) - "Tests format %z with whole minutes." + "Test format %z with whole minutes." (formatz-should-equal (fz-make+zone 0 30) "+00:30") ;has hours even though 0 (formatz-should-equal (fz-make-zone 0 30) "-00:30") (formatz-should-equal (fz-make+zone 0 4) "+00:04") @@ -819,7 +819,7 @@ The functions in `pattern-mod' are composed left to right." ) (defun formatz-nonzero-seconds-helper (form-string pattern-mod) - "Tests format %z with non-0 seconds." + "Test format %z with non-0 seconds." ;; non-0 seconds are always included (formatz-should-equal (fz-make+zone 0 0 50) "+00:00:50") (formatz-should-equal (fz-make-zone 0 0 50) "-00:00:50") @@ -848,7 +848,7 @@ The functions in `pattern-mod' are composed left to right." ) (defun formatz-hours-big-helper (form-string pattern-mod) - "Tests format %z with hours that don't fit in two digits." + "Test format %z with hours that don't fit in two digits." (formatz-should-equal (fz-make+zone 101) "+101:00") (formatz-should-equal (fz-make+zone 123 10) "+123:10") (formatz-should-equal (fz-make-zone 123 10) "-123:10") @@ -857,7 +857,7 @@ The functions in `pattern-mod' are composed left to right." ) (defun formatz-seconds-big-helper (form-string pattern-mod) - "Tests format %z with hours greater than 99 and non-zero seconds." + "Test format %z with hours greater than 99 and non-zero seconds." (formatz-should-equal (fz-make+zone 123 0 30) "+123:00:30") (formatz-should-equal (fz-make-zone 123 0 30) "-123:00:30") (formatz-should-equal (fz-make+zone 120 0 4) "+120:00:04") @@ -868,30 +868,30 @@ The functions in `pattern-mod' are composed left to right." ;; use the above test cases for multiple formats. (defun formatz-mod-del-colons (string) - "Returns STRING with any colons removed." + "Return STRING with any colons removed." (string-replace ":" "" string)) (defun formatz-mod-add-00 (string) - "Returns STRING with \"00\" appended." + "Return STRING with \"00\" appended." (concat string "00")) (defun formatz-mod-add-colon00 (string) - "Returns STRING with \":00\" appended." + "Return STRING with \":00\" appended." (concat string ":00")) (defun formatz-mod-pad-r10 (string) - "Returns STRING padded on the right to 10 characters." + "Return STRING padded on the right to 10 characters." (concat string (make-string (- 10 (length string)) ?\s))) (defun formatz-mod-pad-r12 (string) - "Returns STRING padded on the right to 12 characters." + "Return STRING padded on the right to 12 characters." (concat string (make-string (- 12 (length string)) ?\s))) ;; Convenience macro for generating groups of test cases. (defmacro formatz-generate-tests (form-strings hour-mod mins-mod secs-mod big-mod secbig-mod) - "Defines tests for time formats FORM-STRINGS. + "Define tests for time formats FORM-STRINGS. FORM-STRINGS is a list of formats, each \"%z\" or some variation thereof. Each of the remaining arguments is an unquoted list of the form @@ -925,7 +925,7 @@ the other expected results for hours greater than 99 with non-zero seconds." ert-test-list (list `(ert-deftest ,(intern (concat "formatz-" form-string "-hhmm")) () - ,(concat "Tests time-stamp format " form-string + ,(concat "Test time-stamp format " form-string " with whole hours or minutes.") (should (equal (formatz ,form-string (fz-make+zone 0)) ,(car hour-mod))) @@ -934,13 +934,13 @@ the other expected results for hours greater than 99 with non-zero seconds." ,(car mins-mod))) (formatz-nonzero-minutes-helper ,form-string ',(cdr mins-mod))) `(ert-deftest ,(intern (concat "formatz-" form-string "-seconds")) () - ,(concat "Tests time-stamp format " form-string + ,(concat "Test time-stamp format " form-string " with offsets that have non-zero seconds.") (should (equal (formatz ,form-string (fz-make+zone 0 0 30)) ,(car secs-mod))) (formatz-nonzero-seconds-helper ,form-string ',(cdr secs-mod))) `(ert-deftest ,(intern (concat "formatz-" form-string "-threedigit")) () - ,(concat "Tests time-stamp format " form-string + ,(concat "Test time-stamp format " form-string " with offsets that are 100 hours or greater.") (should (equal (formatz ,form-string (fz-make+zone 100)) ,(car big-mod))) @@ -981,7 +981,7 @@ the other expected results for hours greater than 99 with non-zero seconds." ;; The legacy exception for %z in time-stamp will need to remain ;; through at least 2024 and Emacs 28. (ert-deftest formatz-%z-spotcheck () - "Spot-checks internal implementation of time-stamp format %z." + "Spot-check internal implementation of time-stamp format %z." (should (equal (format-time-offset "%z" (fz-make+zone 0)) "+0000")) (should (equal (format-time-offset "%z" (fz-make+zone 0 30)) "+0030")) (should (equal (format-time-offset "%z" (fz-make+zone 0 0 30)) "+000030")) @@ -1104,7 +1104,7 @@ the other expected results for hours greater than 99 with non-zero seconds." ;;; Illegal %z formats (ert-deftest formatz-illegal-options () - "Tests that illegal/nonsensical/ambiguous %z formats don't produce output." + "Test that illegal/nonsensical/ambiguous %z formats don't produce output." ;; multiple options (should (equal "" (formatz "%_-z" 0))) (should (equal "" (formatz "%-_z" 0)))