org-mode の予定表で祝日を明記する

Emacs の org-mode はスケジュール管理機能があって、
(define-key global-map "\C-ca" 'org-agenda)
した状態で C-c a a を押すと TODO が時系列順に並ぶ( agenda view )。計画を立てるときに便利だ。
しかし、 agenda view には祝日を明記する機能はない(本当はあった。追記参照)。 h を押せば祝日が表示されるが *Org Agenda* バッファには表示されないので使いづらい。 org-agenda で使えるようにするには別個の org-mode なファイルを作成し、 org-agenda-files に追加してやればよい。

org ファイルが ~/memo 以下にあるとする。すなわち、こんな設定になっているものとする。

(setq org-directory "~/memo/")

そして、今年の祝日を出すようにするには、 ~/memo/holidays.2009.org という祝日ファイルを作成して、 org-agenda-files に追加する。たとえば、こんな感じに。 format-time-string を使っているのは今年の年を計算するため。

(setq org-agenda-files (list org-default-notes-file
                             (format-time-string "~/memo/holidays.%Y.org")))

さて、祝日ファイルを作成する。祝日ファイルは以下のような形式をとる。

* 祝日
** 元日
  CLOSED: <2009-01-01 >

** 成人の日
  CLOSED: <2009-01-12 >

** 建国記念の日
  CLOSED: <2009-02-11 >

(略)

CLOSED と書いているのがミソで、これを読み込ませると *Org Agenda* バッファはこんな感じに祝日を表記してくれる。

(略)
Wednesday  11 February 2009
  agenda:     18:29-18:45 Clocked:   (0:16) DONE one-key バッファを右側のフレームにもっていくとどうなる?
  agenda:     18:58-19:02 Clocked:   (0:04) DONE rct-fork って ruby19 対応してたっけ?
  holidays.2009:建国記念の日
(略)

で、未来の祝日ファイルを作成する。秒数が 32 ビット整数という制限がある場合、 2038 年以降は扱えない。そのため、 2009 〜 2037 年の祝日ファイルを生成する。日本の祝日は Emacs のカレンダーに日本の祝日を設定する - http://rubikitch.com/に移転しました を参考に japanese-holidays.el をインストールしておく。以下の式を評価すると ~/memo/holidays.2009.org 〜 ~/memo/holidays.2037.org が生成される。

;; (find-sh0 "ls -l ~/memo/holi*")
(require 'calendar)
(require 'holidays)
;; (install-elisp "http://www.meadowy.org/meadow/netinstall/export/799/branches/3.00/pkginfo/japanese-holidays/japanese-holidays.el")
(require 'japanese-holidays)
(setq holiday-org-dir "~/memo/"
      calendar-holidays (append japanese-holidays local-holidays other-holidays))
(loop for year from 2009 to 2037 do
      (let ((calendar-date-display-form '((format "<%4s-%02d-%02d >" year
                                                  (string-to-int month)
                                                  (string-to-int day)))))
        (save-window-excursion
          (save-excursion
            (list-holidays year year)
            (set-buffer "*Holidays*")
            (setq buffer-read-only nil)
            (goto-char 1)
            (insert "* 祝日\n")
            (while (not (eobp))
              (when (search-forward ": " nil t)
                (let ((date (buffer-substring (point-at-bol) (match-beginning 0)))
                      (holiday (buffer-substring (match-end 0) (point-at-eol))))
                  (delete-region (point-at-bol) (point-at-eol))
                  (insert "** " holiday "\n  CLOSED: " date "\n"))))
            (write-region 1 (point-max) (format "%sholidays.%s.org"
                                                holiday-org-dir year))))))

[2009/02/17]

SCHEDULED ではなくて CLOSED に修正。そうすればゴミが出てこなくなる。

[2009/02/21] 追記

nanasi さん情報ありがとうございます。

* Calendar
%%(org-calendar-holiday)
** TODO 〜

このようにすると祝日が表示されました。