0

I want to collect statistics about some clocked events; more specifically I need to count the number of clocked events (belonging to some subtree for instance) whose duration is in some predefined range (e.g. at least 4 hours but less than 5 hours).

For instance, in the following subtree

*** Week 11 [2018-03-10 Sat] → [2018-03-16 Fri] :CLOCKBOOK: CLOCK: [2018-03-16 Fri 09:00]--[2018-03-16 Fri 13:45] => 4:45 CLOCK: [2018-03-15 Thu 09:00]--[2018-03-15 Thu 13:30] => 4:30 CLOCK: [2018-03-13 Tue 09:00]--[2018-03-13 Tue 13:45] => 4:45 CLOCK: [2018-03-12 Mon 09:00]--[2018-03-12 Mon 14:00] => 5:00 CLOCK: [2018-03-10 Sat 18:00]--[2018-03-10 Sat 21:00] => 3:00 :END:

The function should return 3 How could I achieve this?

1
  • I don't see why you used the org-mode tag, so I removed it. If it is relevant, please consider updating the question to show the relevance.
    – Drew
    Mar 10 '19 at 18:59
1

my-count-clocks in the following Elisp section defines a function that counts clocks in the current org-mode section. It does not descent into sub-sections. You can easily modify my-count-clocks to fit your special needs, e.g., work recursive on sub-sections.

That function has a predicate function as argument. The predicate gets a timestamp as argument and should return non-nil if that timestamp is to be counted.

An example for such a timestamp is given as my-pred. my-pred is non-nil for timestamps that tick at least 4 hours and shorter than 5 hours.

The other functions in the Elisp code are just helpers.

(defun org-element-parse-headline (&optional granularity visible-only)
  "Parse current headline.
GRANULARITY and VISIBLE-ONLY are like the args of `org-element-parse-buffer'."
  (let ((level (org-current-level)))
    (org-element-map
    (org-element-parse-buffer granularity visible-only)
    'headline
      `(lambda (el)
     (and
      (eq (org-element-property :level el) ,level)
      (<= (org-element-property :begin el) (point))
      (<= (point) (org-element-property :end el))
      el))
      nil 'first-match 'no-recursion)))

(defun my-count-clocks (pred)
  "Counting clocks fulfilling PRED in current subsection."
  (interactive "a Predicate:")
  (let* ((headline (org-element-parse-headline))
     (section (org-element-map
              headline
              'section
            #'identity
            nil 'first-match))
     (clocks (org-element-map section 'clock (lambda (clock) (org-element-property :value clock))))
     (num (cl-count-if pred clocks)))
    (when (called-interactively-p 'any)
      (message "Number of clocks: %d" num))
    num))

(eval
 `(defun decode-time-subtract (a b)
    "Decode time difference between A and B."
    (cl-mapcar #'-
           (decode-time (time-subtract a b))
           ',(butlast (decode-time '(0 0)) 3))))

(defun my-pred (timestamp)
  "Example predicate.
Non-nil for timestamp that clicks at least 4 hours and less than 5 hours."
  (let ((b (org-timestamp--to-internal-time timestamp))
    (e (org-timestamp--to-internal-time timestamp t)))
    (cl-multiple-value-bind (sec minute hour day month year) (decode-time-subtract e b)
      ;; Put the condition of your choice here:
      (and (eq year 0) (eq month 0) (eq day 0)
       (>= hour 4)
       (< hour 5))
      )))
1
  • Great answer! Thanks a lot
    – Wilder
    Mar 12 '19 at 12:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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