]> git.vanrenterghem.biz Git - www2.vanrenterghem.biz.git/blob - source/posts/emacs_calendar.org
Voeg post ivm CalDAV en orgmode toe.
[www2.vanrenterghem.biz.git] / source / posts / emacs_calendar.org
1 :PROPERTIES:
2 :CREATED:  [2025-03-05 Wed 19:57]
3 :END:
4 #+date: <2025-03-05 Wed 22:08>
5 #+title: Using Emacs Org mode to manage my appointments.
6 #+filetags: :emacs:Linux:automation:elisp:
7 #+OPTIONS: \n:t
9 #+BEGIN_PREVIEW
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.
17 #+END_PREVIEW
19 Graphically, this results in a a system as shown hereunder:
21 #+BEGIN_SRC dot :results file :file ../assets/caldav-diagram.png :exports results
22   digraph G {
23   server [label="Nextcloud CalDAV server"];
24   org [label="Emacs Org mode", color = "purple"];
25   server -> laptop;
26   laptop -> server;
27   server -> phone [label = "DAVx5"];
28   phone -> server;
29   laptop -> org [label = "org-caldav", fontcolor = "purple"];
30   org -> laptop;
31   laptop -> Firefox;
32   Firefox -> server;
33   }
34 #+END_SRC
36 #+RESULTS:
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.
41 #+BEGIN_SRC org
42   ,* 2025
43   ,** 2025-01 January
44   ,*** New Year lunch
45   ,:PROPERTIES:
46   ,:location: Our place
47   ,:END:
48   Lunch with family to celebrate the new year.
49   <2025-01-01 Wed 11:30>--<2025-01-01 Wed 15:00>
50   ,** 2025-02 February
51   ,*** New Year's resolutions progress review
52   <2025-02-01 Sat>--<2025-02-02 Sun>
53 #+END_SRC
54   
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]].
57 2025 / April
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                         |
63 |                           |                           |                           |                           |                           |                           |                           |
64 |                           |                           |                           |                           |                           |                           |                           |
65 +---------------------------+---------------------------+---------------------------+---------------------------+---------------------------+---------------------------+---------------------------+
66 | 6                         | 7                         | 8                         | 9                         | 10                        | 11                        | 12                        |
67 |                           |                           |                           |                           |                           |                           |                           |
68 |                           |                           |                           |                           |                           |                           |                           |
69 +---------------------------+---------------------------+---------------------------+---------------------------+---------------------------+---------------------------+---------------------------+
70 | 13  Passover              | 14                        | 15                        | 16                        | 17                        | 18  Good Friday           | 19                        |
71 |                           |                           |                           |                           |                           |                           |                           |
72 |                           |                           |                           |                           |                           |                           |                           |
73 +---------------------------+---------------------------+---------------------------+---------------------------+---------------------------+---------------------------+---------------------------+
74 | 20  Easter Sunday         | 21  First Day of Ridvan   | 22                        | 23                        | 24                        | 25                        | 26                        |
75 |                           |                           |                           |                           |                           |                           |                           |
76 |                           |                           |                           |                           |                           |                           |                           |
77 +---------------------------+---------------------------+---------------------------+---------------------------+---------------------------+---------------------------+---------------------------+
78 | 27                        | 28                        | 29  Ninth Day of Ridvan   | 30                        | 1                         | 2  Twelfth Day of Ridvan  | 3                         |
79 |                           |                           |                           |                           |                           |                           |                           |
80 |                           |                           |                           |                           |                           |                           |                           |
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"
90       :jump-to-captured t
91       :empty-lines 1
92       :tree-type month
93       :time-prompt t)))
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)
103               "--"
104               (format-time-string (org-time-stamp-format t) end-time))))
105 #+END_SRC
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]].