[comp.emacs] insert time/date and signature

cdr@symbol.UUCP (Constantine Rasmussen - Sun ECD) (09/09/88)

I use this for my insert date function.  It's in a file that gets
loaded from my .emacs.

=======================================================
;;; date function (useful for logging times in job notes, etc ...)
(defun insert-date-and-time (&optional use-long-form)
  "Args: (&OPTIONAL USE-LONG-FORM)
Returns value from call-process.
Insert the current date and time at point.  Use of a prefix argument
will invoke long form, ie, \"Tue, Jul 12, 1988, 02:17:44 PM\".
Always ends with a newline."

  (interactive "P")
  (call-process "date"
		nil t nil
		(if use-long-form
		    "+%a, %h %d, 19%y, %r"
		    "+%D, %H:%M")))

(global-set-key "t" 'insert-date-and-time)

mesard@bbn.com (Wayne Mesard) (09/09/88)

From article <8809081924.AA09732@symbol.sunecd.com>, by cdr@symbol.UUCP (Constantine Rasmussen - Sun ECD):
> (defun insert-date-and-time (&optional use-long-form)
>   "Args: (&OPTIONAL USE-LONG-FORM)
> Returns value from call-process.
> Insert the current date and time at point.  Use of a prefix argument
> will invoke long form, ie, \"Tue, Jul 12, 1988, 02:17:44 PM\".
> Always ends with a newline."
> 
>   (interactive "P")
>   (call-process "date"
> 		nil t nil
> 		(if use-long-form
> 		    "+%a, %h %d, 19%y, %r"
> 		    "+%D, %H:%M")))
> 
> (global-set-key "t" 'insert-date-and-time)
> 
> 

GNU Emacs has a (current-time-string) function.  (Like the spaghetti
sauce commercials: "It's in der!")  So something like this might do the
trick, without a subprocess:

 (defun insert-stamp ()
   "Inserts timestamp and userid as: Day MMM DD HH:MM:SS YYYY -- USER NAME"
   (interactive)
   (insert (current-time-string) " -- " (user-full-name) )
 )

This has the disadvantage of outputting the time in that bizarre
ctime(3) format.  But it would be trivial to add some "substring" calls
to get it to do the right thing.

-- 
unsigned *Wayne_Mesard();  "There are tons of people who are well adjusted
MESARD@BBN.COM              that have zits."
BBN, Cambridge, MA                                    -EN

eichin@ATHENA.MIT.EDU ("Mark W. Eichin") (09/09/88)

{I sent this only to fischer, but then saw the complicated answer and
figured I'd post...}

   Date: 8 Sep 88 16:07:06 GMT
   Sender: arpa-unix-emacs-request@bbn.com
   Reply-To: Scott Fischer <fischer%umn-cs.uucp@bbn.com>
   Organization: University of Minnesota, Dept. of CSci.

   Does anyone out there have a keybinding defintion that will insert
   the current time or date along with an identification string at the
   current point.  For example, I would like to type "M-x date" or define
   that to a keystroke and it would insert.
	   Thu Sep 8 10:59:40 CDT 1988  -- Scott W. Fischer

What emacs? I have code for GNUemacs, M-x stardate, which gives me a
very compact form: [eichin:19880908.1807EST] The code follows;
however, for what you want (in GNU) you could just do:

(defun date () 
  "Insert a date label into the current buffer"
  (interactive)
  (insert (current-time-string) " -- " (user-full-name)))

Thu Sep  8 18:24:17 1988 -- Mark W. Eichin

(the second line is what happens when you run M-x date.) Note that
this is *MUCH* faster than actually forking a date subprocess, even if
you add elisp code to format the date. (I did use that solution once,
but needed the speed and came up with this one...)
  I keep stardate bound to ^X^J, and use it to mark comments in code...

				Mark Eichin
			<eichin@athena.mit.edu>
		SIPB Member & Project Athena ``Watchmaker'' 


;;; stardate.el
;;; insert something like [eichin:19880309.0843EST] into a file, as a
;;; nerdly sort of timestamp.
;;;					[eichin:19880309.0843EST]
;;; There MUST be some way of speeding this up...
;;; sigh. there is. look at the rcslogs for the old icky version.
;;;					[eichin:19880309.0936EST]

(defvar stardate_el-RCS-id)
(setq stardate_el-RCS-id
      "$Header: stardate.el,v 1.2 88/03/09 09:44:01 eichin Exp $")

(defconst month-day-alist 
  '(("Jan"."01") ("Feb"."02") ("Mar"."03") ("Apr"."04") ("May"."05")
    ("Jun"."06") ("Jul"."07") ("Aug"."08") ("Sep"."09") ("Oct"."10")
    ("Nov"."11") ("Dec"."12"))
  "assoc list of months/numeric string numbers. See calendar.el.")

(defvar stardate-timezone "EST")

(setq date (current-time-string))
(defun insert-stardate ()
  "Put stardate at point."
  (interactive)
  (let ((date (current-time-string)))
    (insert "[" (getenv "USER") ":" 
	    (substring date -4 nil)	; yyyy
	    (cdr (assoc (substring date 4 7)
			month-day-alist)) ; MM
	    (let ((d (substring date 8 9)))
	      (if (equal d " ") "0" d))
	    (substring date 9 10)	; d
	    "."
	    (substring date 11 13)	; hh
	    (substring date 14 16)	; mm
	    stardate-timezone
	    "]")))

cdr@symbol.UUCP (Constantine Rasmussen - Sun ECD) (09/09/88)

   Wayne Mesard writes:

   GNU Emacs has a (current-time-string) function.  (Like the spaghetti
   sauce commercials: "It's in der!")  So something like this might do the
   trick, without a subprocess:

I don't know about other folks but I've had real bad luck with emacs
updating its time string with something that was accurate.
Sorry, I haven't spent the time to look into where the problem was
comming from but it was off by as much as 10-15 minutes so I stopped
using it til I could debug it.  I was running 18.41 (on a Sun under
SunOS 3.2 on a 3/50 without clock problems) at the time.

I'll use (current-time-string) for a while and see how it goes.

jr@bbn.com (John Robinson) (09/09/88)

In article <8809091320.AA10206@symbol.sunecd.com>, cdr@symbol (Constantine Rasmussen - Sun ECD) writes:
>I don't know about other folks but I've had real bad luck with emacs
>updating its time string with something that was accurate.

When you call (current-time-string), it calls time() and ctime() [GNU,
version 18.51 does, anyway].  Any clock problems must by in Unix or
the Sun.
--
/jr
jr@bbn.com or bbn!jr

karl@haddock.ima.isc.com (Karl Heuer) (09/10/88)

In article <29477@bbn.COM> mesard@bbn.com (Wayne Mesard) writes:
>GNU Emacs has a (current-time-string) function. ...
>This has the disadvantage of outputting the time in that bizarre
>ctime(3) format.  But it would be trivial to add some "substring" calls
>to get it to do the right thing.

It would be better yet if, instead of having to reverse-engineer the string
format, we could just invoke an elisp equivalent to localtime() (probably
returning a nine-element list of integers, or maybe eight integers and a
boolean).  It shouldn't be too hard to add this.

Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint

pdc@otter.hple.hp.com (Damian Cugley) (09/10/88)

Wayne Mesard:						<mesard@bbn.com>
> GNU Emacs has a (current-time-string) function. [...]
>  (defun insert-stamp ()
>    "Inserts timestamp and userid as: Day MMM DD HH:MM:SS YYYY -- USER NAME"
>    (interactive)
>    (insert (current-time-string) " -- " (user-full-name) )
>  )
> 
> This has the disadvantage of outputting the time in that bizarre
> ctime(3) format.  But it would be trivial to add some "substring" calls
> to get it to do the right thing.

Funny you should mention that.  I was bored this morining and one of the
things I did was write some funcs to reformat Notes (that is, netnews)
files, which includes a date-reforming function (quoted at the end of
this article).  I was just reading comp.emacs in order to ask something
about it!

This was designed to be invoked just after inserting the date in the
`Notes format', and has been altered in the obvious way to fit the ctime
dates (or any similar format).  Then we might define:

(defun timestamp ()
  "Documentation goes here.  Be creative."
  (interactive) ;of course
  (insert (user-full-name) ", " (current-time-string))
  (format-date))

Example:
	Damian Cugley, 9 Sep 1988


pdc
--
  /-------------------\/-------------------------\/------------------------\ 
  | Damian Cugley =@= || pdc@hplb.lb.hp.co.uk    || ...!mcvax!ukc!hplb!pdc |  
  | HPLabs Bristol UK || pdc%otter@hplabs.HP.COM ||   ...!hplabs!otter!pdc |  
  \-------------------/\-------------------------/\------------------------/  

;;;;;;;;;;;;;;;;;;;;;;;;;SNIP HERE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;	Reformat the date

(defconst silly-date-regexp
	"\\([a-zA-Z]+\\) +\\([a-zA-Z]+\\) +\\([0-9]?[0-9]\\) +\\([0-9:]+\\) +\\([0-9]+\\)"
	"This is a regexp used to translate dates from the ctime fromat
to one I happen to like.  The five parameters are the day of week, month
day-of-month, time-of-day and year.")

(defconst my-date-format
	"\\3 \\2 \\5"
	"How I like the date to appear.  The sequence `\\DIGIT' is translated
as in query-replace-regexp; see silly-date-format for the meaning of these
`parameters'.")

;; Version for Notes:
;;(defconst silly-date-regexp
;;  "\\([0-9]?[0-9]:[0-9][0-9]\\)[\t ]+[apAP][mM][ \n]+\\([a-zA-Z]+\\)[\t ]+\\([0-9]+\\),?[ \t]*\\([0-9]+\\)\\>"
;;  "A regexp that represents the time-and-date as produced by many
;;American programs.")

;;(defconst my-date-format
;;  "\\3 \\2 \\4"
;;  "*How I like the date formatted - `\\\\DIGIT' (where DIGIT is an
;;integer from 1 to 9) represents `parameters' (that is, \\(...\\)
;;groupings from silly-date-regexp.")

(defun format-date ()
  "Reformat the date string before point on this line  into a format I like."
  (interactive)
  (if (re-search-backward
       silly-date-regexp
       (save-excursion (beginning-of-line) (point))
       t)
      (replace-match my-date-format)
    (message "?? There doesn't seem to be a date on this line.")))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

weemba@garnet.berkeley.edu (Matthew P Wiener) (09/10/88)

In article <7243@haddock.ima.isc.com>, karl@haddock (Karl Heuer) writes:
>It would be better yet if, instead of having to reverse-engineer the string
>format, we could just invoke an elisp equivalent to localtime().

You're right.  Failing that, I have the following functions, currently
unused, from Gnews:

gnews-time
  Return current time in ((YY MM DD).(HH MM SS)) format.
gnews-time-form
  Convert a list L in the form (YY MM DD) into "YYMMDD".
gnews-date-back
  From a date L in (YY MM DD) format, return the list for N days earlier.
gnews-date-forward
  From a date L in (YY MM DD) format, return the list for N days later.
----------------------------------------------------------------------
;;; Copyright (C) 1987 by Matthew P Wiener; all rights reserved.

;;; These functions are distributed as described in the GNU Emacs
;;; General Public license.

(defun gnews-time ()
  "Return current time in ((YY MM DD).(HH MM SS)) format."
  ;; This assumes (current-time-string) returns
  ;; something like: "Sun Jan 10 00:00:00 1988"
  (let* ((months '(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec))
	 (time (current-time-string))
	 (mm (read-from-string time 4))
	 (dd (read-from-string time (cdr mm)))
	 (d (car dd))
	 (di (cdr dd))
	 (h (read (substring time (+ 0 di) (+ 2 di))))
	 (m (read (substring time (+ 3 di) (+ 5 di))))
	 (s (read (substring time (+ 6 di) (+ 8 di))))
	 (y (read (substring time (+ 11 di) (+ 13 di))))
	 (mo (- 13 (length (memq (car mm) months)))))
    (cons (list y mo d) (list h m s))))

(defun gnews-time-form (l)		; RLS
  "Convert a list L in the form (YY MM DD) into \"YYMMDD\"."
  (apply 'format "%02d%02d%02d" l))

(defun gnews-date-back (l n)
  "From a date L in (YY MM DD) format, return the list for N days earlier.
As in NNTP, we assume the 2-digit year YY is centered on 2000."
  (let* ((y (car l))
	 (m (gnadr l))
	 (p (1- m))
	 (d (gnaddr l))
	 (z '(31 28 31 30 31 30 31 31 30 31 30 31)))
    (while (<= d n)
      (setq n (- n d)
	    m (if (< 0 p) p (setq y (1- y)) 12)
	    p (1- m)
	    d (nth p z))
      (if (= y -1) (setq y 99))
      (if (and (= m 2) (zerop (% y 4)) (not (zerop y))) (setq d (1+ d))))
    (list y m (- d n))))

(defun gnews-date-forward (l n)
  "From a date L in (YY MM DD) format, return the list for N days later.
As in NNTP, we assume the 2-digit year YY is centered on 2000."
  (let* ((y (car l))
	 (m (gnadr l))
	 (p (1+ m))
	 (z '(31 28 31 30 31 30 31 31 30 31 30 31))
	 (d (gnaddr l))
	 (c (nth (1- m) z))
	 (e (+ n d)))
    (if (and (= m 2) (zerop (% y 4)) (not (zerop y))) (setq c (1+ c)))
    (while (< c e)
      (setq e (- e c)
	    m (if (< p 13) p (setq y (1+ y)) 1)
	    p (1+ m)
	    c (nth (1- m) z))
      (if (= y 100) (setq y 0))
      (if (and (= m 2) (zerop (% y 4)) (not (zerop y))) (setq c (1+ c))))
    (list y m e)))

ucbvax!garnet!weemba	Matthew P Wiener/Brahms Gang/Berkeley CA 94720
"Nil sounds like a lot of kopins! I never got paid nil before!" --Groo

jcgs@harlqn.UUCP (John Sturdy) (09/20/88)

Here is the code I've been using to do this for the last year or so:

;;; date.el
;;; Last edited: Tue Sep 20 11:58:42 1988 by jcgs (John Sturdy) on harlqn

;;; This code maintains dates and signatures in files, removing the old
;;; date each time.

(defvar last-edited-pattern
  "Last edited: "
  "*The regexp after which the time-stamp is written by the
function \"time-stamp\". See also \"last-edited-end-pattern\".")

(defvar last-edited-end-pattern
  "$"
  "*The function \"time-stamp\" deletes the text between the first match of
\"last-edited-pattern\" (which see) and the following match of
\"last-edited-end-pattern\", then writes the time-stamp between them.
This pattern normally marks the end of the current line."
)

(defvar by-line
  (concat
   " by "
   (user-login-name)
   " ("
   (user-full-name)
   (if (boundp 'nick-name)
       (concat " - " nick-name ")")
     ")")
   " on "
   (system-name))
  "The user-id and name of the user, and the name of the host machine,
in a form suitable for time-stamping.  If the user has defined the
variable \"nick-name\" before loading \"date\", it is included after
the real name, separated from it by a dash.")

(defun time-stamp ()
  "Update the \"Last edited:\" field in a buffer. Can be used on
\"write-file-hook\" for automatic time-stamping. The time-stamp
includes the date and time, the user's user-id and real name, and a
nick-name if the variable \"nick-name\" was already defined when the
\"date\" package was loaded. The \"Last edited:\" marker string must
occur in the first 3000 characters of the buffer."
  (interactive)
  (save-excursion
    (goto-char (point-min))
    (if
        (re-search-forward last-edited-pattern 3000 t)
        (let
            ((start-of-date (point)))
          (re-search-forward last-edited-end-pattern)
          (delete-region (point) start-of-date)
          (insert (current-time-string))
          (insert by-line)))))

(defun date-line ()
  "Insert a date marker line, in outline-mode's top-level format."
  (interactive)
  (beginning-of-line 2)
  (insert "* ")
  (insert (current-time-string))
  (insert by-line)
  (insert "\n"))

(setq write-file-hook 'time-stamp)      ; mark time, date on all files
                                        ; containing "Last edited:" as
                                        ; they are saved
;;; end of date.el

heins@spp2.UUCP (Michael T. Heins) (09/27/88)

John- thanks for a useful function.  I modified the last expression
in your function to make it work with my GNU Emacs 18.51 as follows:

(setq write-file-hooks
	(append
	    write-file-hooks
	    '(time-stamp)))   ; mark time, date on all files
                              ; containing "Last edited:" as
                              ; they are saved

dch@cci632.UUCP (David C. Howland) (04/11/89)

The following contains a history.el package, an autoload for the package
and hook to enable it.

This package was built on top of the date.el, time-stamp function
written by John Sturdy (uunet!mcvax!ukc!eagle!icdoc!qmc-cs!harlqn!jcgs)

What I have changed/added is that along with the time stamp and user
field,  the user is prompted for an optional comment. Each
change-log-stamp is inserted after "Last Edited:" and the the previous
entry pushed down in the file (similar to add-change-log-entry). As in 

-----
Last Edited:

Fri Apr  7 10:27:12 1989 by David C. Howland (dch at ccird3)
	 And so on and on.

Fri Apr  7 10:12:50 1989 by David C. Howland (dch at ccird3)
	 Second Change.

Fri Apr  7 10:02:11 1989 by David C. Howland (dch at ccird3)
	 Original Comment.

-----
This was written for GNU Emacs. If anyone has constructive comments on
how to improve this, please mail or post them. If you make changes to
enhance history.el please mail or post them also.

-------------------------------------------------------------------------------
Added the following to your .emacs

(autoload 'change-log-stamp "history"
	 "\
Update the last edited field in a buffer and add a comment"
	t)

; Mark time, date and optional comment on all files containing
; "Last Edited:", as they are saved.
(setq write-file-hooks '(list change-log-stamp))

----------- cut here and save in history.el -----------------------------------
;;; history.el
;;; Last Edited:
;;; 
;;; Tue Apr  4 17:37:06 1989 by David C. Howland (dch at ccird3)
;;; 	 Added defvar for history-search-limit. Up'd the limit from 3000
;;; 	 characters to 5000
;;; 


(defvar history-min-comment-length 10
  "*The minimum length that a \"change-log-stamp\" comment must be.
If set to 0 there is no minimum.")

(defvar history-buffer "*History*"
  "*The buffer name to get history information from.")

(defvar history-search-limit 5000
  "*The marker string \"Last Edited:\" must occur in the first 5000 characters")

(defvar history-mode-map nil)

(if history-mode-map
    nil
  (setq history-mode-map (make-sparse-keymap))
  (define-key history-mode-map "\C-c?"    'history-help)
  (define-key history-mode-map "\C-c\C-a" 'history-abort)
  (define-key history-mode-map "\C-c\C-c" 'history-exit)
  (define-key history-mode-map "\C-x\C-s" 'history-exit)
)

(defvar last-edited-pattern
  "Last Edited:"
  "*The regexp after which the change-log-stamp is written by the
function \"change-log-stamp\".")

(defvar by-line
  (concat " by " (user-full-name) " (" (user-login-name)
	  (if (boundp 'nick-name)
	      (concat " - " nick-name ")")
	    )
	  " at " (system-name) ")")
  "The user-id and name of the user, and the name of the host machine,
in a form suitable for change-log-stamping.  If the user has defined the
variable \"nick-name\" before loading \"date\", it is included after
the real name, separated from it by a dash.")


(defun change-log-stamp ()
  "Update the \"Last edited:\" field in a buffer. Can be used on
\"write-file-hooks\" for automatic updating. The change-log-stamp
includes the date and time, the user's user-id and real name, a
nick-name if the variable \"nick-name\" was already defined when the
\"history\" package was loaded and an optional comment.
The \"Last Edited:\" marker string must occur in the first 5000
characters (defvar \"history-search-limit\") of the buffer. Uses
the characters from the beginning of the line that \"Last Edited\" 
was on, up-to the 'L', if any, as the comment characters to precede
any text that is inserted."
  (interactive)
  (save-excursion
    (goto-char (point-min))
    (if
        (re-search-forward last-edited-pattern history-search-limit t)
        (let
            ((start-of-date (point)))

	  (save-excursion
	    (beginning-of-line)
	    (setq here (point))
	    (re-search-forward last-edited-pattern)
	    (backward-word 2)
	    (setq comments (buffer-substring here (point)))
	    )
	  
	  (setq prefix-line (concat comments "	 "))
	  (setq ThisBuffer (buffer-name))
	  (save-window-excursion
	    (setq insert-text-here (point)) ; save place where text is to go.
	    (pop-to-buffer history-buffer t)
	    (erase-buffer)
	    (set-buffer-modified-p nil)
	    (or (eq major-mode 'indented-text-mode)
		(progn
		  (indented-text-mode)
		  (setq left-margin 8)
		  (setq fill-column 72)
		  (setq fill-prefix prefix-line)))
	    (auto-fill-mode 1)
	    (indent-to left-margin)
	    (use-local-map history-mode-map)
	    (message 
	     "Enter log message. Type C-c C-c when done, C-c ? for help.")
	    (recursive-edit)
	    (kill-buffer history-buffer))
	  )
      )
    )
  (setq junk nil)			; cause defun to return nil
  )

(defun history-exit ()
  "Leave the recursive edit of an history log message."
  (interactive)
  (if (> (buffer-size) history-min-comment-length)
      (progn
	(switch-to-buffer history-buffer)
	(goto-char (point-min))
	(delete-char 1)
	(switch-to-buffer ThisBuffer)
	(goto-char insert-text-here)	; move to where text is to go
	(insert "\n" comments "\n")
	(insert comments (current-time-string))
	(insert by-line)
	(insert "\n" prefix-line)
	(insert-buffer history-buffer)
	(exit-recursive-edit))
    (progn
      (error
       "Log must be greater than %d characters!"
       history-min-comment-length))
    )
  )

(defun history-abort ()
  "Abort the recursive edit of an history log message."
  (interactive)
  (exit-recursive-edit)
  )

(defun history-help()
  "Describes \"change-log-stamp\"  key bindings. See \"change-log-stamp\" function.
Related variables: history-min-comment-length, history-buffer and 
                   history-search-limit.

The following commands are available:
\\{history-mode-map}
"
  
  (interactive)
  (describe-function 'history-help)
)

tale@pawl.rpi.edu (David C Lawrence) (04/12/89)

Could people who post code like this please let the rest of us know
how it is better than other packages that have made it around out
there?  We use two history packages here, whist.el and header.el, and
I can't see how this is any better.  Actually, in this case, it fairly
easy to tell that I don't need to install history.el here by looking
at what it produces ... not that much different from whist.

If you did not know that the whist and header existed, perhaps you
should get a hold of the free lisp code directory from Dave Sill
<dsill@relay.nswc.navy.mil> and apropos through that.  I find it is
usually best to consult the directory before writing some new code
because it might already exist.  (This is general advice, not just for
David.)

I'm still trying to find out which of the two pascal modes is better;
I'd like to provide one or the other for my users but I don't want
both around.  (Seems as though the FSF settled on VIP in 18.53; vi.el
is still there but no longer in the info tree.)
--
      tale@rpitsmts.bitnet, tale%mts@itsgw.rpi.edu, tale@pawl.rpi.edu