public
Created

  • Download Gist
org-calculate-free-time.el
Emacs Lisp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
;; use appt-convert-time instead if appt is loaded
(defun iy/convert-time (time2conv)
"Convert hour:min[am/pm] format TIME2CONV to minutes from midnight.
A period (.) can be used instead of a colon (:) to separate the
hour and minute parts."
;; Formats that should be accepted:
;; 10:00 10.00 10h00 10h 10am 10:00am 10.00am
(let ((min (if (string-match "[h:.]\\([0-9][0-9]\\)" time2conv)
(string-to-number (match-string 1 time2conv))
0))
(hr (if (string-match "[0-9]*[0-9]" time2conv)
(string-to-number (match-string 0 time2conv))
0)))
;; Convert the time appointment time into 24 hour time.
(cond ((and (string-match "pm" time2conv) (< hr 12))
(setq hr (+ 12 hr)))
((and (string-match "am" time2conv) (= hr 12))
(setq hr 0)))
;; Convert the actual time into minutes.
(+ (* hr 60) min)))
 
(defun iy/org-get-entries (files date)
(let (entry entries)
(dolist (file files)
(catch 'nextfile
(org-check-agenda-file file)
(setq entry (org-agenda-get-day-entries
file date :scheduled :timestamp))
(setq entries (append entry entries))))
entries))
 
(defun sacha/org-calculate-free-time (date start-time end-of-day)
"Return a cons cell of the form (TASK-TIME . FREE-TIME) for DATE, given START-TIME and END-OF-DAY.
DATE is a list of the form (MONTH DAY YEAR).
START-TIME and END-OF-DAY are the number of minutes past midnight."
(save-window-excursion
(let* ((entries (iy/org-get-entries (org-agenda-files) date))
(total-unscheduled 0)
(total-gap 0)
(last-timestamp start-time)
scheduled-entries)
;; For each item on the list
(dolist (entry entries)
(let ((time (get-text-property 1 'time entry))
(effort (org-get-effort (get-text-property 1 'org-hd-marker entry))))
(cond
((and time
(string-match "\\([^-]+\\)-\\([^-]+\\)" time))
(push (cons
(save-match-data (iy/convert-time (match-string 1 time)))
(save-match-data (iy/convert-time (match-string 2 time))))
scheduled-entries))
((and time
(string-match "\\([^-]+\\)\\.+" time)
(not (eq effort nil)))
(let ((start (save-match-data (iy/convert-time (match-string 1 time))))
(effort (save-match-data (iy/convert-time effort))))
(push (cons start (+ start effort)) scheduled-entries)))
((not (eq effort nil))
(setq total-unscheduled (+ (iy/convert-time effort)
total-unscheduled))))))
;; Sort the scheduled entries by time
(setq scheduled-entries (sort scheduled-entries (lambda (a b) (< (car a) (car b)))))
(while scheduled-entries
(let ((start (car (car scheduled-entries)))
(end (cdr (car scheduled-entries))))
(cond
;; are we in the middle of this timeslot?
((and (>= last-timestamp start)
(<= last-timestamp end))
;; move timestamp later, no change to time
(setq last-timestamp end))
;; are we completely before this timeslot?
((< last-timestamp start)
;; add gap to total, skip to the end
(setq total-gap (+ (- start last-timestamp) total-gap))
(setq last-timestamp end)))
(setq scheduled-entries (cdr scheduled-entries))))
(if (< last-timestamp end-of-day)
(setq total-gap (+ (- end-of-day last-timestamp) total-gap)))
(cons total-unscheduled total-gap))))

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.