Adding Lunar Phases to Emacs' Org AgendaPosted on 19th of February 2023 | 911 words
As some of you may know, I’ve been a practising Buddhist for some time, focusing mainly on the teachings of Early Buddhism and Theravada. One aspect of this practice is keeping up with Uposatha, which is also present in other schools of Buddhism. Wikipedia describes Uposatha as follows :
The Uposatha (Sanskrit: Upavasatha) is a Buddhist day of observance, in existence from the Buddha’s time (600 BCE), and still being kept today by Buddhist practitioners. The Buddha taught that the Uposatha day is for “the cleansing of the defiled mind,” resulting in inner calm and joy. On this day, both lay and ordained members of the sangha intensify their practice, deepen their knowledge and express communal commitment through millennia-old acts of lay-monastic reciprocity. On these days, the lay followers make a conscious effort to keep the Five Precepts or (as the tradition suggests) the ten precepts. It is a day for practicing the Buddha’s teachings and meditation.
Uposatha days change from lunar month to lunar month, so there are no set days for those. But generally speaking, Uposatha is observed about once a week in accordance to the lunar phases. Which lunar phases are observed depends on the culture, but there are four phases to this: the new moon, the full moon and two quarter moons between those. Theravada cultures generally observe all four, but for example, in Sri Lanka, they tend to only observe the new and the full moon.
How these Uposatha days are calculated is quite interesting, and there is a paper published on GitHub by Gambhiro Bhikkhu about that.
Personally, I have followed these moon days by adding those to my
Apple Calendar via the iCal link provided in the repository above, and
I’ve been quite happy with that. Lately, though, I noticed that I tend
to easily miss these days since I don’t often have notifications on or
my calendar open when these days happen, which made me easily miss
those. That got me thinking that it would be pretty cool to have those
lunar phases on my
emacs since that is most likely always open for
me and I’m already mainly doing my time management in
So I started digging around on how these could be easily added to my
org-agenda, and then I found a built-in command from
emacs that is
at least the first step there called
M-x lunar-phases, which
basically prints lunar phases of the last, current and next month. So
I started hacking around to try to get these to my Agenda view.
Not long after starting my hacking in this, I found a nice doc piece
about some ad-hoc tweaks to be made to the agenda from
which actually made exactly what I wanted. What it involves is that I
need to build an agenda file with these lunar phases so that the
Agenda view in
emacs picks those up.
So first, I needed to add some arbitrary file to my
(use-package org :custom (org-agenda-files '(<your other agenda files> "/path/to/lunar.org")))
(setq org-agenda-files '(<your other agenda files> "/path/to/lunar.org"))
I happen to have all my agenda files in my
Documents folder on my
macOS, so they just get synced across my devices, but naturally, you
can use any path you want.
lunar.org file itself is pretty simple. Basically, we add a
header to it with a single diary sexp calling a function,
org-lunar-phases, which we soon define:
* Lunar phase +CATEGORY: Lunar %%(org-lunar-phases)
org-lunar-phases itself either isn’t too complicated. It
involves that we pass in the current day to it, which gets passed in
in a relatively odd way via the diary sexp we used above, and after
that we just parse the
lunar-phase-list with the current day, or
month and year in this case, since
lunar-phase-list returns a list
of lunar phases for the next three months.
(require 'cl-lib) ;; Pass current day to `org-lunar-phases', which is annoyingly in a stupid :: format, (MM DD YYYY). (with-no-warnings (defvar date)) (defun org-lunar-phases () "Show lunar phase in Agenda buffer." (require 'lunar) (let* ((phase-list (lunar-phase-list (nth 0 date) (nth 2 date))) (phase (cl-find-if (lambda (phase) (equal (car phase) date)) phase-list)) (lunar-phase-names '("● New Moon" "☽ First Quarter Moon" "○ Full Moon" "☾ Last Quarter Moon"))) (when phase ;; Return the phase to the agenda file. (setq ret (concat (lunar-phase-name (nth 2 phase)))))))
Naturally, you can get all fancy with those
adding emojis and whatnot if you’re into it. But in all simplicity,
that is how you can add lunar phases to your agenda, and it shows as
following in there:
10 days-agenda (W08-W09): Monday 20 February 2023 W08 Lunar: ● New Moon Tuesday 21 February 2023 Wednesday 22 February 2023 Thursday 23 February 2023 Friday 24 February 2023 Saturday 25 February 2023 Sunday 26 February 2023 Monday 27 February 2023 W09 Lunar: ☽ First Quarter Moon Tuesday 28 February 2023 Wednesday 1 March 2023
One thing that I noticed from this was the fact the GitHub link above
that I mentioned. That happens to produce a little bit different
results for these phases. Every once in a while, some phases differ
just a tiny bit. There is a mention that the calculation method used
in that paper was related to how these days are calculated in
Mahānikāya in Thailand, so there might be some variance compared to
M-x lunar-phases. But personally, I feel it’s close enough and
quite beneficial to me.