From mboxrd@z Thu Jan 1 00:00:00 1970 From: Paul Sexton Subject: Some useful timestamp s-expressions Date: Wed, 18 Aug 2010 20:22:16 +0000 (UTC) Message-ID: Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Return-path: Received: from [140.186.70.92] (port=38366 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1Olp9k-00088E-OL for emacs-orgmode@gnu.org; Wed, 18 Aug 2010 16:22:45 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.69) (envelope-from ) id 1Olp9e-0006rn-6O for emacs-orgmode@gnu.org; Wed, 18 Aug 2010 16:22:39 -0400 Received: from lo.gmane.org ([80.91.229.12]:49653) by eggs.gnu.org with esmtp (Exim 4.69) (envelope-from ) id 1Olp9d-0006rZ-QE for emacs-orgmode@gnu.org; Wed, 18 Aug 2010 16:22:34 -0400 Received: from list by lo.gmane.org with local (Exim 4.69) (envelope-from ) id 1Olp9Z-0003Nu-UF for emacs-orgmode@gnu.org; Wed, 18 Aug 2010 22:22:31 +0200 Received: from rp.young.med.auckland.ac.nz ([130.216.140.20]) by main.gmane.org with esmtp (Gmexim 0.1 (Debian)) id 1AlnuQ-0007hv-00 for ; Wed, 18 Aug 2010 22:22:29 +0200 Received: from psexton by rp.young.med.auckland.ac.nz with local (Gmexim 0.1 (Debian)) id 1AlnuQ-0007hv-00 for ; Wed, 18 Aug 2010 22:22:29 +0200 List-Id: "General discussions about Org-mode." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: emacs-orgmode-bounces+geo-emacs-orgmode=m.gmane.org@gnu.org Errors-To: emacs-orgmode-bounces+geo-emacs-orgmode=m.gmane.org@gnu.org To: emacs-orgmode@gnu.org In org, timestamps can be in the usual angle-bracket format, eg <2010-08-19 +2w>, or you can use lisp s-expressions. These are in the same format as the s-expressions used in the 'diary'/'calendar' emacs packages. I only discovered these recently but have been able to use them to schedule some complex recurring items. I thought I would share the code here. 1. Recurring items with a limited number of occurrences For example, 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. AFAIK Org'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)> 2. Public holiday that is "the nearest Monday to DATE" In New Zealand each regional capital has an "Anniversary Day". The date of Auckland's anniversary day is "the nearest Monday to 29 January". Put this in your .emacs: (defun calendar-nearest-to (target-dayname target-day target-month) "Recurring event that occurs in the nearest TARGET-DAYNAME to the date TARGET-DAY, TARGET-MONTH each year." (interactive) (let* ((dayname (calendar-day-of-week date)) (target-date (list target-month target-day (calendar-extract-year date))) (days-diff (abs (- (calendar-day-number date) (calendar-day-number target-date))))) (and (= dayname target-dayname) (< days-diff 4)))) Now we can schedule Auckland Anniversary Day. The first argument, 1, means Monday (days of the week are numbered starting with Sunday=0). *** Auckland Anniversary Day <%%(calendar-nearest-to 1 29 1)> 3. Public holiday on "the 4th Monday in October". This does not require any additions to .emacs: *** Labour Day (NZ) <%%(diary-float 10 1 4)> 4. Easter Easter's date moves around from year to year according to a complicated set of criteria which I do not claim to understand. However the following code will allow you to schedule recurring events relative to Easter sunday. Note: the function da-easter is from: http://github.com/soren/elisp/blob/master/da-kalender.el Put the following in your .emacs: (defun da-easter (year) "Calculate the date for Easter Sunday in YEAR. Returns the date in the Gregorian calendar, ie (MM DD YY) format." (let* ((century (1+ (/ year 100))) (shifted-epact (% (+ 14 (* 11 (% year 19)) (- (/ (* 3 century) 4)) (/ (+ 5 (* 8 century)) 25) (* 30 century)) 30)) (adjusted-epact (if (or (= shifted-epact 0) (and (= shifted-epact 1) (< 10 (% year 19)))) (1+ shifted-epact) shifted-epact)) (paschal-moon (- (calendar-absolute-from-gregorian (list 4 19 year)) adjusted-epact))) (calendar-dayname-on-or-before 0 (+ paschal-moon 7)))) (defun da-easter-gregorian (year) (calendar-gregorian-from-absolute (da-easter year))) (defun calendar-days-from-easter () "When used in a diary sexp, this function will calculate how many days are between the current date (DATE) and Easter Sunday." (- (calendar-absolute-from-gregorian date) (da-easter (calendar-extract-year date)))) Now we can schedule the public holidays associated with Easter as recurring events. Good Friday is 2 days before "Easter", Easter Monday is one day after. *** Good Friday <%%(= -2 (calendar-days-from-easter))> *** Easter Sunday <%%(= 0 (calendar-days-from-easter))> *** Easter Monday <%%(= 1 (calendar-days-from-easter))> Paul