Add time to a deadline

| categories: org-mode | tags:

Table of Contents

I have an application where an org-file is a template with some due dates in it. I would like to update the deadlines to make them all relative to today. In this post I explore a way to do that. The strategy is to find deadlines, parse the time out of the time stamp, add an appropriate amount of time, and replace the time stamp. For this exercise, we use this org-file, which has one DEADLINE of "2014-01-13 Mon", and I want to add 60 days to the time stamp.

Amazingly, emacs can parse time strings into a format that it can understand. I do not claim to understand what this function returns, but it is some representation of time that emacs understands.

(date-to-time "<2014-01-13 Mon>")

(21203 11392)

Now, we can add time to that format. Let us say I want to add 60 days. In emacs, we add seconds to a time, so 60 days is 60 days * 24 hours * 60 minutes * 60 seconds, or in elisp: (* 60 24 60 60).

(let ((sixty-days (seconds-to-time (* 60 24 60 60))))
  (time-add (date-to-time "<2014-01-13 Mon>") sixty-days))

(21282 18048 0 0)

That does not make too much sense, so we can use another function to format it like a new time stamp.

(let ((sixty-days (seconds-to-time (* 60 24 60 60))))
  (format-time-string "<%Y-%m-%d %a>"
                      (time-add (date-to-time "<2014-01-13 Mon>") sixty-days)))

<2014-03-13 Thu>

Beautiful. We just got a timestamp that is 60 days later than the original timestamp. Now we just search forward to find deadline, get the time stamp, add the time to it, and replace the line. I specifically want to change deadlines, so we will develop a regular expression for that. Here is a block that searches forward for a DEADLINE, parses it, adds 60 days to it, and replaces the deadline. The regular expression is limited to timestamps that look like <yyyy-mm-dd day>, i.e. no warnings or repeaters are found. In this post, there is subheading that looks like this initially:

#+BEGINEXAMPLE

1 s1

#+ENDEXAMPLE

(progn
  (save-excursion
    ;; go to timestamp
    (re-search-forward "DEADLINE:\\s-*<\\(\\([0-9]\\{4\\}\\)-\\([0-9]\\{2\\}\\)-\\([0-9]\\{2\\}\\)\\s-\\(Mon\\|Tue\\|Wed\\|Thu\\|Fri\\|Sat\\|Sun\\)\\)>")
    (let ((ts (match-string 1)) ;; this is the timestamp
          (sixty-days (seconds-to-time (* 60 24 60 60)))
          (new-ts))
      (setq new-ts (format-time-string "    DEADLINE: <%Y-%m-%d %a>"
                                       (time-add (date-to-time ts) sixty-days)))
      ;; now we kill the old time stamp, and insert the new one
      (beginning-of-line)
      (kill-line)
      (insert new-ts))))

After we run the code above, the deadline looks like this: #+BEGINEXAMPLE

2 s1

#+ENDEXAMPLE

We succeeded in moving it by 60 days. An interesting application of this would be to make all the deadlines in an org-file relative to some baseline date. For example, you have a series of deadlines for assignments throughout a semester, and it would be tedious to update these by hand. Suppose you could just establish a new beginning date, and make all deadlines relative to that date with a command. That seems useful.

3 s1

Copyright (C) 2014 by John Kitchin. See the License for information about copying.

org-mode source

Org-mode version = 8.2.5h

Discuss on Twitter