emacs-orgmode
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Orgmode] Some useful timestamp s-expressions


From: Paul Sexton
Subject: [Orgmode] Some useful timestamp s-expressions
Date: Wed, 18 Aug 2010 20:22:16 +0000 (UTC)
User-agent: Loom/3.14 (http://gmane.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





reply via email to

[Prev in Thread] Current Thread [Next in Thread]