わさっきhb

大学(教育研究)とか ,親馬鹿とか,和歌山とか,とか,とか.

タイムスタンプ挿入のEmacs Lisp,作り直し

 ふだんはWindowsEmacsで文章やプログラムを書いています.
 文章を書いているとき,たまに,年月日・時分秒の情報(タイムスタンプ)が必要になることがあります.M-x instimeで,編集箇所にタイムスタンプを挿入するよう,instimeを定義していました.
 最近これを実行すると,「Wed Feb 17 21:28:48 東京 (標準時) 2021」のような文字列が挿入されるのに気づきました.「東京 (標準時)」がタイムゾーンですが,こんなのが貼り付けられても,嬉しくありません.
 といったところで,instimeの定義を見直すと…

(defun instime ()
  "Timestamp insertion function"
  (interactive)
  (let ((time (current-time-string)))
    (insert (substring time 0 20)
            (nth 1 (current-time-zone))
            " "
            (substring time -4))))

 なんだか変なことをしています.scratchバッファで,「(current-time-string)」と「(current-time-zone)」を評価(貼り付けてからC-j)してみました.

(current-time-string)
"Wed Feb 17 21:33:19 2021"
(current-time-zone)
(32400 #("東京 (標準時)" 0 8 (charset cp932-2-byte)))

 ということで,上記のinstimeの処理内容が見えてきました.一時使用の変数timeに,"Wed Feb 17 21:33:19 2021"という文字列を格納してから,「(substring time 0 20)」で,"Wed Feb 17 21:33:19"という文字列を得ます.「(nth 1 (current-time-zone))」は"東京 (標準時)"です.空白1文字のあと,「(substring time -4)」は"2021"です.インサートされる文字列は,"Wed Feb 17 21:33:19 東京 (標準時) 2021"というわけです.
 「(current-time-string)」の結果はいいのですが,「(current-time-zone)」で得られる情報は,期待しないものなのです.この出力,昔はASCII文字で構成したのに,あるときから日本語が入るようになった,と思われます.
 かわりに,タイムゾーン込みのタイムスタンプを出力する方法を調査しました.自作のEmacs Lispのコードの中に「(format-time-string "%Y%m%d" (current-time))」というのがあり,これを検索してみると,よいコードが見つかりました.

 このうちISO 8601 Formatのコードが,手を加えるにはよさそうです.

(concat
 (format-time-string "%Y-%m-%dT%T")
 ((lambda (x) (concat (substring x 0 3) ":" (substring x 3 5)))
  (format-time-string "%z")))

 lambdaの行で何をしているのかが気になり,再びscratchバッファで試しました.

(format-time-string "%z")
"+0900"
((lambda (x) (concat (substring x 0 3) ":" (substring x 3 5)))
  (format-time-string "%z"))
"+09:00"

 なるほど,ラムダ式を入れないと,タイムゾーンは「+0900」になり,これを「+09:00」に変換するために,lambdaを使用している,と.
 あとは自分用に関数にする作業です.「(concat」から始まる式で,得られるのは,文字列です.M-xなになにを実行すると,編集箇所にタイムスタンプを挿入してくれるよう,手を加えて,自分が使うことになりそうなEmacs Lispの関数を作りました.以下より参照・ダウンロードができます.

 何をするかは,このファイルの先頭に書いた通りです.Windows + Emacs 27.1のほか,Ubuntu + Emacs 26.3でも動作確認をしました.

;; M-x insert-timestamp-default (またはM-x its)で Wed Feb 17 22:18:46 2021
;; M-x insert-timestamp-htmlcomment (またはM-x itsh)で <!-- 2021-02-17 22:18:52 +09:00 --> (と改行)
;; M-x insert-timestamp-unixtime (またはM-x itsu)で 1613567937
;; M-x insert-timestamp-iso (またはM-x itsi)で 2021-02-17T22:19:01+09:00

 4つの関数のうち,insert-timestamp-unixtimeだけ全く異なる処理内容です.昔のスクリプトファイルでは,instimeのあとに,instimeuというのを定義していて,Unix時間*1を挿入するというものなのですが,これをコピーして関数名をinsert-timestamp-unixtimeに変更したのでした.


 こういう処理は昔から多くの人が異なる方法で記述してきたんだろうなと思いながら,検索すると,海外のフォーラムを見つけました.

 タイトルの次に「Asked 12 years」とあり,質問者情報には「asked Oct 30 '08 at 21:56」と記されています.
 最上位の回答が「C-u M-! date」です.こんな方法で,タイムスタンプが挿入できるのかと,試してみると…
 「現在の日付: 2021/02/17」と「新しい日付を入力してください: (年-月-日)」という,Windowsのdateコマンドを実行した結果が,バッファに挿入されました.日付を変えるわけにいきません(この方法では変えられません).

*1:例として書いた値の「1613567937」について,Rubyが実行可能な端末で「ruby -e "puts Time.at(1613567937)"」を実行すれば,結果は「2021-02-17 22:18:57 +0900」となり,適切な数値であることが確認できます.