2 :CREATED: [2025-03-05 Wed 19:57]
4 #+date: <2025-03-05 Wed 22:08>
5 #+title: Using Emacs Org mode to manage my appointments.
6 #+filetags: :emacs:Linux:automation:elisp:
10 ~Memento, homo, quia pulvis es, et in pulverem reverteris.~
12 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.
14 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 [[https://www.researchgate.net/publication/3419713_Open_Calendar_Sharing_and_Scheduling_with_CalDAV][Dusseault, Lisa & Whitehead, J.. (2005). Open Calendar Sharing and Scheduling with CalDAV. Internet Computing, IEEE. 9. 81 - 89. 10.1109/MIC.2005.43. ]])
16 The calendar data from the server is synchronised with my phone using [[https://www.davx5.com/][DAVx5]] where I currently use the [[https://github.com/FossifyOrg/Calendar][Fossify Calendar]] to display and make or alter appointments, and on my laptop using [[https://github.com/dengste/org-caldav][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.
19 Graphically, this results in a a system as shown hereunder:
21 #+BEGIN_SRC dot :results file :file ../assets/caldav-diagram.png :exports results
23 server [label="Nextcloud CalDAV server"];
24 org [label="Emacs Org mode", color = "purple"];
27 server -> phone [label = "DAVx5"];
29 laptop -> org [label = "org-caldav", fontcolor = "purple"];
37 [[file:../assets/caldav-diagram.png]]
39 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.
48 Lunch with family to celebrate the new year.
49 <2025-01-01 Wed 11:30>--<2025-01-01 Wed 15:00>
51 ,*** New Year's resolutions progress review
52 <2025-02-01 Sat>--<2025-02-02 Sun>
55 Alternatively, I can view my appointments on a traditional calendar layout using the [[https://github.com/kiwanami/emacs-calfw][Emacs calendar framework or calfw]].
58 [ < ] [ > ] [Today] [Day] [Week] [Two Weeks] [Month]
59 +---------------------------+---------------------------+---------------------------+---------------------------+---------------------------+---------------------------+---------------------------+
60 | Sunday | Monday | Tuesday | Wednesday | Thursday | Friday | Saturday |
61 +---------------------------+---------------------------+---------------------------+---------------------------+---------------------------+---------------------------+---------------------------+
62 | 30 | 31 | 1 April Fools' Day | 2 | 3 | 4 | 5 |
65 +---------------------------+---------------------------+---------------------------+---------------------------+---------------------------+---------------------------+---------------------------+
66 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
69 +---------------------------+---------------------------+---------------------------+---------------------------+---------------------------+---------------------------+---------------------------+
70 | 13 Passover | 14 | 15 | 16 | 17 | 18 Good Friday | 19 |
73 +---------------------------+---------------------------+---------------------------+---------------------------+---------------------------+---------------------------+---------------------------+
74 | 20 Easter Sunday | 21 First Day of Ridvan | 22 | 23 | 24 | 25 | 26 |
77 +---------------------------+---------------------------+---------------------------+---------------------------+---------------------------+---------------------------+---------------------------+
78 | 27 | 28 | 29 Ninth Day of Ridvan | 30 | 1 | 2 Twelfth Day of Ridvan | 3 |
81 +---------------------------+---------------------------+---------------------------+---------------------------+---------------------------+---------------------------+---------------------------+
83 I also set up a new capture template, allowing the quick creation of an appointment using C-c c followed by a.
85 #+BEGIN_SRC emacs-lisp
86 (org-capture-templates
87 '(("a" "Appointment" entry
88 (file+olp+datetree "~/Nextcloud/notes/calendar-nextcloud.org")
89 "* %?\n :PROPERTIES:\n :location: %^{Location}\n :END:\n%(fv/org-capture-appointment-timestam)\n\n"
95 (defun fv/org-capture-appointment-timestamp (&optional duration)
96 "Get an Org timestamp for an appointment.
97 Prompt for a start time, calculate the end time by adding DURATION (default 30
98 minutes), and return a formatted Org timestamp with start and end times."
99 (let* ((duration (or duration 30))
100 (start-time (org-read-date t t nil "From:"))
101 (end-time (time-add start-time (seconds-to-time (* duration 60)))))
102 (concat (format-time-string (org-time-stamp-format t) start-time)
104 (format-time-string (org-time-stamp-format t) end-time))))
107 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 [[https://github.com/tkf/org-mode/blob/c2ebeea6f68f2ef804d387c238e4acccf655dc64/lisp/org-capture.el#L897-L907][some logic in the template engine]] at the moment.
109 Full setup can be found in [[http://git.vanrenterghem.biz/Dotty.git/blob/7c1ae2a1b7c0674664d97d06a61c232920a72b90:/emacs/.emacs.d/init.el][Dotty, my dot files repository]].