I’ve been looking for an offline calendaring solution that will allow smooth syncing via Dropbox or an alternative. I originally tried Sunbird but there was always issues with duplicate events. I’ve been wanting a plain-text variant to avoid these issues, but the existing solutions are not ideal.
Simultaneously, I’ve been looking for an excuse to learn org-mode for a while. It is always hyped as a terrific solution to any outlining scenario (which, truly, calendaring is), but has a steep learning curve for anything past a very basic outline.
After spending months periodically searching online for a good tutorial on using org-mode as a calendar, I found no complete tutorial, but I began to accumulate enough bits and pieces to figure out the setup. The below is both for my benefit, to document how my system works in the event of data-loss or memory-loss, and to attempt a unified tutorial on org-mode calendaring.
This setup was accomplished on Emacs 24.3.50.1 (though I suspect earlier 24.x versions will suffice) with org-mode 8.0.3 (again, I suspect earlier 8.x versions will work).
First, decide where you are going to keep your files. I’d suggest their
own directly, maybe ~/.emacs.d/org
. Create the
directory. touch
a file in there
named whatever.org
. You’ll probably want multiple files for
each type of calender (to avoid any one getting overwhelmingly large) but
you can create the rest later.
Orgmode’s categories are analogous to individual calendars in Google Calender or iCal. You can put each event into a category, and then do things such as color them by category, or show only certain categories.
There are two ways to organize your categories. First, just have one per file. I prefer this option as it keeps from having too long of a file, and I find it easier to think of each category as completely independent. The second way would be to use a single file, and have each category in its own subgroup.
As I’ve said, at its core, orgmode is an outlining system, so org-mode files tend to (generally) follow this syntax:
* First level
** Second level
*** Third level
** back to second
* New first level
** Second level under second top
So the single *
is the top-most level, **
is
nested below it, etc.
Calendar events will follow the same structure. Generally, you’ll have the top level by a category, and then all events under that category will be in the second level, but you could add more structure to it by nesting a sub-category with its own events.
Here’s some very simple events.
* Work
** Meeting with Bob
<2013-06-12 Wed 13:00-14:00>
** Call with Sally
<2013-06-14 Fri 3:30pm>
The time stamp should be fairly self-explanatory. The day of the week and
time are both completely optional. For time, note that two times separated
by a -
are the duration of the event, while a single time is
simply a start-time (a reminder perhaps). You can enter military time or
am/pm. (Note, for future snippets, I will often ignore the *
level, just assume they’re in a larger file under a top level.)
To make an event spanning multiple days (or a longer alternative to the duration above), use this.
** Trip to LA
<2013-07-10>--<2013-07-15>
Finally, for a recurring event, you can do this.
** Team Meeting
<2013-05-10 Fri 10:00-11:00am +1w>
The +1w
implies that this event will repeat every week at the
same time & date, ad infinitum. The number can be changed, and the
usual codes can replace w
(e.g. d
for days, etc)
(See below for more advanced repeating events.)
Now, some editing of your config file (.emacs
or init.el
, either in ~
or
~/.emacs.d/
). First, you’ll need to add
<setq org-agenda-files '("~/.emacs.d/org")>
Of course, change that directory as needed. All .org
files
living there will be used for the calendar, assuming an event has a
time-stamp.
Now, call M-x org-agenda
to view your calendar. (Note: You
can use C-h f org-agenda
to see the default key-bindings, and
you can use a line like (global-set-key (kbd "C-c a")
'org-agenda)
to modify it.)
Hopefully, you now see your weekly schedule! You can visit the Org manual for a full list of key bindings, but the most useful ones are
f
and b
: Go forward or backwards in time.
v
followed by m
, y
or w
: View a month, a year, or a week at a time
respectively.
.
: Return to today.
Enter
: While your cursor is on an event, open that event in
its original file.
f
and b
: Go forward or backwards in time.
r
: Rebuild the agenda (if you’ve been editing files).
By default, the file-name of your .org
file are your
file-name, so if you named your file calendar.org
, you might
be seeing
Wednesday 12 June 2013
calendar: 1:00pm- 2:00pm Meeting with Bob
The calendar:
tag can be made more informative by use
PROPERTIES. For example, taking the sample from above,
* Work
:CATEGORY: Work
** Meeting with Bob
<2013-06-12 Wed 13:00-14:00>
** Call with Sally
<2013-06-14 Fri 3:30pm>
Now, the calender would look like
Wednesday 12 June 2013
Work: 1:00pm- 2:00pm Meeting with Bob
The :CATEGORY
will apply to a given event and all below it.
So if you have your work file, you can add a second level, for
example ** Off-site Events
, give it a category
like :CATEGORY: Off-site
and then put events below it,
*** An off-site visit
, then even if this is nested in the
Work file, it will have the Off-site:
category.
Here’s some settings I find useful. These go in your config file as above.
<setq org-agenda-start-on-weekday 0>
<setq org-agenda-timegrid-use-ampm 1>
<setq org-agenda-time-grid '((daily today today)
#("----------------" 0 16 (org-heading t))
(800 1000 1200 1400 1600 1800 2000)))>
The following fairly self-explanatory code in your config file will color
events. You can
use this page to
get a list of colors. Simply modify the list of (color-org-header
"tag" "color")
to your needs.
(add-hook 'org-finalize-agenda-hook
(lambda ()
(save-excursion
(color-org-header "Personal:" "green")
(color-org-header "Birthdays:" "gold")
(color-org-header "Work:" "orange")
(color-org-header "Off-site:" "SkyBlue4"))))
(defun color-org-header (tag col)
""
(interactive)
(goto-char (point-min))
(while (re-search-forward tag nil t)
(add-text-properties (match-beginning 0) (point-at-eol)
`(face (:foreground ,col)))))
You can use diary sexp entries to do more complicated scheduling. There are plenty of places online to see details, for example here, but here’s an example to get you started.
** 10:00-11:30am Twice weekly!
<%%(org-class 2013 9 3 2013 12 11 1)>
<%%(org-class 2013 9 3 2013 12 11 3)>
This says this event is scheduled from 9/3/2013 to 12/11/2013, on every
Monday (the final 1 in the first time-stamp) and Wednesday (the final 3 in
the second time-stamp). Note that the time is in the **
line!
Without further comment, here’s a neat way to have holidays and birthdays in your agenda.
* Birthday
#+CATEGORY: Holidays
%%(org-calendar-holiday)
#+CATEGORY: Birthdays
%%(diary-anniversary 9 12 1957) John, %d y.o.
%%(diary-anniversary 4 3 1962) Sally, %d y.o.
Future goals: Auto-removing past events
Home | Back to Misc Code & SoftwareThis work is licensed under CC BY-NC 4.0