Memento, homo, quia pulvis es, et in pulverem reverteris.
After some months of trying out a prototype approach and tweaking it, I believe to have landed on a viable system to manage my appointments seamlessly from within Emacs, on my Android phone and any other calendar application.
I use a calendar self-hosted on a Nextcloud instance, accessible through the CalDAV protocol - the Distributed Authoring and Versioning protocol for calendar data that came out of Apple in the early 2000s (interesting details on that in Dusseault, Lisa & Whitehead, J.. (2005). Open Calendar Sharing and Scheduling with CalDAV. Internet Computing, IEEE. 9. 81 - 89. 10.1109/MIC.2005.43. )
The calendar data from the server is synchronised with my phone using DAVx5 where I currently use the Fossify Calendar to display and make or alter appointments, and on my laptop using org-caldav in GNU Emacs, writing to a Org mode calendar file. I occasionally also use the web-based view from the Nextcloud web client from within a browser.
Graphically, this results in a a system as shown hereunder:
The Org file accessed through Emacs is set up using a date tree as the outline mode of the file. This creates headings by year and by month that can be folded and unfolded using standard functionality from Org mode. That offers a unique way to access appointments - alternatives to have headlines by week exist as well, but I don't have enough appointments to warrant that level of granularity in the outline of the file.
* 2025 ** 2025-01 January *** New Year lunch ,:PROPERTIES: ,:location: Our place ,:END: Lunch with family to celebrate the new year. <2025-01-01 Wed 11:30>--<2025-01-01 Wed 15:00> ** 2025-02 February *** New Year's resolutions progress review <2025-02-01 Sat>--<2025-02-02 Sun>
Alternatively, I can view my appointments on a traditional calendar layout using the Emacs calendar framework or calfw.
2025 / April
[ < ] [ > ] [Today] [Day] [Week] [Two Weeks] [Month]
Sunday | Monday | Tuesday | Wednesday | Thursday | Friday | Saturday |
30 |
31 |
1 April Fools' Day |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 Passover |
14 |
15 |
16 |
17 |
18 Good Friday |
19 |
20 Easter Sunday |
21 First Day of Ridvan |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 Ninth Day of Ridvan |
30 |
1 |
2 Twelfth Day of Ridvan |
3 |
I also set up a new capture template, allowing the quick creation of an appointment using C-c c followed by a.
(org-capture-templates '(("a" "Appointment" entry (file+olp+datetree "~/Nextcloud/notes/calendar-nextcloud.org") "* %?\n :PROPERTIES:\n :location: %^{Location}\n :END:\n%(fv/org-capture-appointment-timestam)\n\n" :jump-to-captured t :empty-lines 1 :tree-type month :time-prompt t))) (defun fv/org-capture-appointment-timestamp (&optional duration) "Get an Org timestamp for an appointment. Prompt for a start time, calculate the end time by adding DURATION (default 30 minutes), and return a formatted Org timestamp with start and end times." (let* ((duration (or duration 30)) (start-time (org-read-date t t nil "From:")) (end-time (time-add start-time (seconds-to-time (* duration 60))))) (concat (format-time-string (org-time-stamp-format t) start-time) "--" (format-time-string (org-time-stamp-format t) end-time))))
One gripe at the moment: the capture template needs a custom function to properly capture a time range, even though the standard Org timestamp can be formatted in a time range easily using syntax like 2pm+1h
to create a 1h block starting at 14:00. When using this within a capture template using the shorthand %^T
which prompts for a date, the timestamp is unfortunately simplified using some logic in the template engine at the moment.
Full setup can be found in Dotty, my dot files repository.
Posted on Wednesday 5 March 2025 at 22:08