; time-stamp: documentation, tests, NEWS

* lisp/time-stamp.el (time-stamp-pattern, time-stamp-count): Document
how to update different time stamps on multiple lines.
* doc/emacs/files.texi (Time stamps): Add an example showing a time
stamp at the end of a file.
* etc/NEWS: Announce time-stamp format additions.
* test/lisp/time-stamp-tests.el: More title-case tests.
This commit is contained in:
Stephen Gildea 2025-02-02 20:14:40 -08:00
parent a62a262397
commit 7f10d2680b
4 changed files with 84 additions and 23 deletions

View file

@ -1072,6 +1072,22 @@ identify and update that custom template:
@end group
@end example
Here is another example, with the time stamp inserted into the last
paragraph of an HTML document. The @code{%%} in the pattern asks for
the default format.
@example
@r{@dots{}}
<p>Last modified: </p>
</body>
</html>
<!--
Local variables:
time-stamp-pattern: "-10/Last modified: %%</p>$"
End:
-->
@end example
@vindex time-stamp-format
By default the time stamp is
formatted according to your locale setting (@pxref{Environment}) and

View file

@ -901,6 +901,30 @@ the 'grep' results editable. The edits will be reflected in the buffer
visiting the originating file. Typing 'C-c C-c' will leave the Grep
Edit mode.
** time-stamp
---
*** 'time-stamp' can up-case, capitalize and down-case date words.
This control can be useful in languages in which days of the week and/or
month names are capitalized only at the beginning of a sentence. For
details, see the built-in documentation for variable 'time-stamp-format'.
Because this feature is new in Emacs 31.1, do not use it in the local
variables section of any file that might be edited by an older version
of Emacs.
---
*** Some historical 'time-stamp' conversions now warn.
'time-stamp-pattern' and 'time-stamp-format' had quietly
accepted several 'time-stamp' conversions (e.g., "%:y") that
have been deprecated since Emacs 27.1 (released in 2020).
These now generate a warning with a suggested migration.
Merely having "(add-hook 'before-save-hook 'time-stamp)"
in your Emacs init file does not expose you to this change.
However, if you set 'time-stamp-format' or 'time-stamp-pattern'
with a file-local variable, you may be asked to update the value.
** TeX modes
+++

View file

@ -248,7 +248,11 @@ your init file, you would be incompatible with other people's files.")
(defvar time-stamp-count 1 ;Do not change!
"How many templates \\[time-stamp] will look for in a buffer.
The same time stamp will be written in each case.
If the value is greater than 1, the same time stamp will be written in
each case. If you want to insert different text on different lines,
then instead of changing this variable, include a newline (written as
\"\\n\") in `time-stamp-format' or the format part of `time-stamp-pattern'.
`time-stamp-count' is best changed with a file-local variable.
If you were to change it in your init file, you would be incompatible
@ -259,26 +263,27 @@ with other people's files.")
(defvar time-stamp-pattern nil ;Do not change!
"Convenience variable setting all `time-stamp' location and format values.
This string has four parts, each of which is optional.
These four parts set `time-stamp-line-limit', `time-stamp-start',
`time-stamp-format', and `time-stamp-end'. See the documentation
for each of these variables for details.
These four parts override `time-stamp-line-limit', `time-stamp-start',
`time-stamp-format' and `time-stamp-end', respectively. See the
documentation for each of these variables for details.
The first part is a number followed by a slash; the number sets the number
of lines at the beginning (negative counts from end) of the file searched
for the time stamp. The number and the slash may be omitted to use the
normal value.
value of `time-stamp-line-limit' as the number.
The second part is a regexp identifying the pattern preceding the time stamp.
This part may be omitted to use the normal pattern.
This part may be omitted to use the value of `time-stamp-start'.
The third part specifies the format of the time stamp inserted. See
the documentation for `time-stamp-format' for details. Specify this
part as \"%%\" to use the normal format.
The third part specifies the format of the time stamp inserted. Specify
this part as \"%%\" to use the value of `time-stamp-format'.
The fourth part is a regexp identifying the pattern following the time stamp.
This part may be omitted to use the normal pattern.
This part may be omitted to use the value of `time-stamp-end'.
The pattern does not need to match the entire line of the time stamp.
The pattern will update time stamp information on multiple lines if the
pattern includes newlines, written as \"\\n\".
These variables are best changed with file-local variables.
If you were to change `time-stamp-pattern', `time-stamp-line-limit',
@ -299,6 +304,11 @@ Examples:
%% time-stamp-pattern: \"newcommand{\\\\\\\\timestamp}{%%}\"
(sets `time-stamp-start' and `time-stamp-end')
// time-stamp-pattern: \"10/Author %L\\nRevised %-d %b %Y$\"
(sets all four variables and updates text on two lines)
See Info node `Time Stamps' for more examples.
See also `time-stamp-count' and `time-stamp-inserts-lines'.")
;;;###autoload(put 'time-stamp-pattern 'safe-local-variable 'stringp)

View file

@ -344,13 +344,12 @@
;; 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, 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))
(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 "%^4a" ref-time1) p4-MON))
@ -401,13 +400,12 @@
;; 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, 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))
(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 "%^4b" ref-time1) p4-JAN))
@ -490,7 +488,7 @@
(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, recommended since 2019
;; implemented since 1997, recommended 2019-2024
(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"))
@ -517,7 +515,7 @@
;; recommended 1997-2019
(should (equal (time-stamp-string "%:m" ref-time1) "1"))
(should (equal (time-stamp-string "%:m" ref-time2) "11"))
;; implemented since 1997, recommended since 2019
;; implemented since 1997, recommended 2019-2024
(should (equal (time-stamp-string "%1m" ref-time1) "1"))
(should (equal (time-stamp-string "%1m" ref-time2) "11"))
;; warned 1997-2019, allowed 2019, recommended (with caveat) since 2024
@ -540,7 +538,7 @@
;; recommended 1997-2019
(should (equal (time-stamp-string "%:M" ref-time1) "4"))
(should (equal (time-stamp-string "%:M" ref-time2) "14"))
;; implemented since 1997, recommended since 2019
;; implemented since 1997, recommended 2019-2024
(should (equal (time-stamp-string "%1M" ref-time1) "4"))
(should (equal (time-stamp-string "%1M" ref-time2) "14"))
;; warned 1997-2019, allowed 2019, recommended (with caveat) since 2024
@ -563,7 +561,7 @@
;; recommended 1997-2019
(should (equal (time-stamp-string "%:S" ref-time1) "5"))
(should (equal (time-stamp-string "%:S" ref-time2) "15"))
;; implemented since 1997, recommended since 2019
;; implemented since 1997, recommended 2019-2024
(should (equal (time-stamp-string "%1S" ref-time1) "5"))
(should (equal (time-stamp-string "%1S" ref-time2) "15"))
;; warned 1997-2019, allowed 2019, recommended (with caveat) since 2024
@ -586,10 +584,12 @@
(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
;; `-' and `_' affect all 2-digit conversions identically.)
;; %-y and %_y warned 1997-2019, changed in 2019
;; (We don't expect these forms to be useful,
;; but we test here so that we can confidently state that
;; all 2-digit conversions behave identically.)
(should (equal (time-stamp-string "%1y" ref-time1) "6"))
(should (equal (time-stamp-string "%1y" ref-time2) "16"))
(should (equal (time-stamp-string "%-y" ref-time1) "6"))
(should (equal (time-stamp-string "%-y" ref-time2) "16"))
(should (equal (time-stamp-string "%_y" ref-time1) " 6"))
@ -619,6 +619,8 @@
(am (format-time-string "%P" ref-time3 t))
(Pm (format-time-string "%p" ref-time1 t))
(Am (format-time-string "%p" ref-time3 t))
(Pm-tc (capitalize (format-time-string "%p" ref-time1 t)))
(Am-tc (capitalize (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 recommended since 1997
@ -644,6 +646,11 @@
(should (equal (time-stamp-string "%^#P" ref-time3) am))
(should (equal (time-stamp-string "%^P" ref-time1) ""))
(should (equal (time-stamp-string "%^P" ref-time3) ""))
;; implemented since 2025
(should (equal (time-stamp-string "%*p" ref-time1) Pm-tc))
(should (equal (time-stamp-string "%*p" ref-time3) Am-tc))
(should (equal (time-stamp-string "%*P" ref-time1) Pm-tc))
(should (equal (time-stamp-string "%*P" ref-time3) Am-tc))
;; reserved for possible adding or removing periods (dots)
(should (equal (time-stamp-string "%:p" ref-time1) Pm))
(should (equal (time-stamp-string "%#:p" ref-time1) pm))
@ -667,6 +674,7 @@
"Test `time-stamp' format %Z."
(with-time-stamp-test-env
(let ((UTC-abbr (format-time-string "%Z" ref-time1 t))
(Utc-abbr (capitalize (format-time-string "%Z" ref-time1 t)))
(utc-abbr (format-time-string "%#Z" ref-time1 t)))
;; implemented and recommended since 1995
(should (equal (time-stamp-string "%Z" ref-time1) UTC-abbr))
@ -674,7 +682,10 @@
(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)))))
(should (equal (time-stamp-string "%^#Z" ref-time1) utc-abbr))
;; implemented since 2025
(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."