This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;; 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)))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment