0

How can I get the duration of a scheduled headline in minutes? As an example, I'd expect the following heading to return 65.

* Foo
  SCHEDULED: <2023-11-19 Sun 10:00-11:05>

What I've tried

  1. org-get-scheduled-time returns the start time as an org-mode time tuple. However, this doesn't include the end time.
2
  • Re: org-get-scheduled-time returning only the start time - that's because SCHEDULED does not imply duration in Org mode. It is only to notify you that you are supposed to start working on something at the indicated date (and possibly time). See Deadlines and Scheduling in the Org mode manual - particularly the note marked Important. As far as Org mode is concerned, it needs to know the start time in order to add the event to the agenda. If you have the grid turned on, a timestamp like the above shows the duration as well...
    – NickD
    Commented Nov 22, 2023 at 18:51
  • ... but that's incidental.
    – NickD
    Commented Nov 22, 2023 at 18:53

2 Answers 2

1

Here's a function that takes a timestamp range as argument and calculates its duration in minutes:

(defun my/org-timestamp-range-duration-in-minutes (ts)
   (if (member (org-element-property :type ts) '(active-range inactive-range))
       (/ (time-subtract (org-timestamp-to-time ts 'end) (org-timestamp-to-time ts)) 60)
     nil))

We take a timestamp object as argument, check that it's a time range (active or inactive), convert the start and end times to internal format, subtract the start time from the end time which returns seconds and divide by 60 to convert to minutes.

If you want to find out the duration of some timestamp range in your Org mode file, use the following invocation with point at the beginning of the timestamp (i.e. the opening < or [ for an active or inactive timestamp resp.):

M-: (my/org-timestamp-range-duration-in-minutes (org-element-timestamp-parser))

E.g. in the following Org mode file, when I run the code block, it moves point to the beginning of the timestamp (previously determined to be 12 by using C-u C-x =) and then uses the above invocation to calculate the duration of the timestamp range in minutes:

* APPT foo
<2023-11-22 Wed 20:00-21:00>


* Code
#+begin_src elisp :results drawer
  (defun my/org-timestamp-range-duration-in-minutes (ts)
    (if (member (org-element-property :type ts) '(active-range inactive-range))
        (/ (time-subtract (org-timestamp-to-time ts 'end) (org-timestamp-to-time ts)) 60)
      nil))

  (save-excursion
    (goto-char 12)
    (my/org-timestamp-range-duration-in-minutes (org-element-timestamp-parser)))
#+end_src

#+RESULTS:
:results:
60
:end:

If you change the 12 to some other point in the buffer (e.g. 13), the type check fails and the function returns nil. If you change the timestamp at position 12 to e.g. <2023-11-22 Wed 20:00> (i.e. not a range), the type check fails there as well. Ranges with different dates work fine: e.g. if you change it to <2023-11-22 Wed 20:00>--<2023-11-23 Thu 21:00> the block gives a result of 1500 minutes (= 25 hours).

0

This doesn't seem optimal and it assumes the timestamp is formatted as <YYYY-MM-DD HH:MM-HH:MM .*>.

(defun summarize-agenda-time--get-scheduled-duration-in-minutes (pos)
  "Return the scheduled duration, in minutes, of the heading at POS, or nil."
  (let ((timestamp (org-entry-get pos "SCHEDULED")))
    (when timestamp
      (let ((timestamp-with-duration-regexp "\\(<.*\\)\\([0-9][0-9]:[0-9][0-9]\\)-\\([0-9][0-9]:[0-9][0-9]\\)\\(.*>\\)"))
        (when (string-match timestamp-with-duration-regexp
                            timestamp)
          (let* ((start-org-time (org-time-string-to-time
                                  (replace-regexp-in-string timestamp-with-duration-regexp
                                                            "\\1\\2\\4"
                                                            timestamp)))
                 (end-org-time (org-time-string-to-time
                                (replace-regexp-in-string timestamp-with-duration-regexp
                                                          "\\1\\3\\4"
                                                          timestamp))))
            (/ (org-time-subtract end-org-time
                                  start-org-time)
               60)))))))
1
  • I think you should write a function that takes a timestamp range as argument and calculates the duration of it in minutes. You should avoid tying it to a keyword (like SCHEDULED) since time stamp ranges occur in many contexts (and SCHEDULED is not - or at least should not be - one of those contexts; see my comment to your question).
    – NickD
    Commented Nov 22, 2023 at 21:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.