Org-mode offers a convenient diary sexp function for setting up a recurring appointment that lasts for a certain period of time, such as a class. It is called org-class and it can be entered as follows:
** Class 7:00pm-9:00pm
<%%(org-class 2009 2 16 2009 4 20 1 10)>
The function above schedules an appointment for every Monday (1) between February 16 and April 20, 2009, except for ISO week 10 (March 1 to March 7).
If you would prefer not to place the timestamp in the headline, you can use the following format:
** Class
<%%(org-class 2009 2 16 2009 4 20 1 10)> 7:00pm-9:00pm Class
In this case, the string following the sexp will be displayed in the agenda.
The function org-class has the following format:
(org-class Y1 M1 D1 Y2 M2 D2 DAYNAME &rest SKIP-WEEKS)
Y1/2, M1/2, and D1/2 indicate the beginning and ending dates. DAYNAME takes the form of a number indicating the day of the week (0 = Sunday, 1 = Monday, and so on...). In addition, one can add an optional argument SKIP-WEEKS to indicate weeks on the calendar that should be skipped. This argument should be expressed as an ISO week number. You can find the number by invoking emacs' built-in calendar (M-x calendar), navigating to the appropriate week, and typing p c (calendar-iso-print-date). If one of the SKIP-WEEKS is the symbol holidays, then any holidays known to the calendar are also skipped.
Here is an alternative method, shared by Paul Sexton on the org mailing list:
Let's say you are taking night classes in Spanish. The class is every Wednesday evening at 7pm, starting on 18 August, and runs for 8 weeks. Org-mode's timestamps do not support limited occurrences of recurrent items -- you have to schedule the item with infinite recurrences, then delete it when it finishes.
To schedule the Spanish classes, put the following in your .emacs:
(defun diary-limited-cyclic (recurrences interval m d y)
"For use in emacs diary. Cyclic item with limited number of recurrences.
Occurs every INTERVAL days, starting on YYYY-MM-DD, for a total of
RECURRENCES occasions."
(let ((startdate (calendar-absolute-from-gregorian (list m d y)))
(today (calendar-absolute-from-gregorian date)))
(and (not (minusp (- today startdate)))
(zerop (% (- today startdate) interval))
(< (floor (- today startdate) interval) recurrences))))
The item in the org file looks like this:
** 19:00-21:00 Spanish lessons
<%%(diary-limited-cyclic 8 7 8 18 2010)>