Finding out if I’m overscheduled
| emacs, orgIf you’re anything like me, your task list is long and growing, but
the time you have is just as fixed. How do you manage that? I handle
that problem by looking at my calendar and my task list together when
I’m planning my day. I tend to be too optimistic about my tasks,
trying to schedule more into my day than I should. Fortunately, Emacs
can help me make sure I don’t overcommit. Here’s how it works.
When I create and schedule tasks, I try my best to add time estimates.
The numbers in the TODO headline represent minutes.
* TODO 15 Announce tea party SCHEDULED: <2007-12-08 Sat> * DONE 30 Drop letters off at post office SCHEDULED: <2007-12-08 Sat> * TODO 60 Write blog post about tasks SCHEDULED: <2007-12-08 Sat> * TODO 60 Make book notes SCHEDULED: <2007-12-09 Sun> * TODO 30 Start on my letter for 2007 SCHEDULED: <2007-12-08 Sat> * TODO 60 Follow up with DemoCamp contacts SCHEDULED: <2007-12-08 Sat> DEADLINE: <2007-12-09 Sun> * TODO 60 Respond to mail SCHEDULED: <2007-12-08 Sat>
Then my custom agenda view looks like this:
Day-agenda:
Saturday 8 December 2007
6:00...... --------------------
8:00...... --------------------
10:00...... --------------------
12:00...... --------------------
14:00...... --------------------
14:00-17:15 Scheduled: TODO Take another driving lesson - emergency stuff
16:00...... --------------------
18:00...... --------------------
20:00...... --------------------
22:00...... --------------------
In 1 d.: TODO 60 Follow up with DemoCamp contacts
Scheduled: TODO 15 Announce tea party
Scheduled: TODO 60 Write blog post about tasks
Scheduled: TODO 30 Start on my letter for 2007
Scheduled: TODO 60 Follow up with DemoCamp contacts
Scheduled: TODO 60 Respond to mail
In 937 d.: 101 things in 1001 days
62.7% load: 225 minutes to be scheduled, 359 minutes free, 134 minutes gap
I’ll need to figure out over the next few weeks what kind of a load
threshold is good (you really don’t want to try for 100%), but at
least it’s visible!
(setq org-agenda-custom-commands
'(("i" "My agenda"
((org-agenda-list nil nil 1)
(sacha/org-load)))
;; ... other stuff goes here
))
(defun sacha/org-show-load ()
"Show my unscheduled time and free time for the day."
(interactive)
(let ((time (sacha/org-calculate-free-time
;; today
(calendar-gregorian-from-absolute (time-to-days (current-time)))
;; now
(let* ((now (decode-time))
(cur-hour (nth 2 now))
(cur-min (nth 1 now)))
(+ (* cur-hour 60) cur-min))
;; until the last time in my time grid
(let ((last (car (last (elt org-agenda-time-grid 2)))))
(+ (* (/ last 100) 60) (% last 100))))))
(message "%.1f%% load: %d minutes to be scheduled, %d minutes free, %d minutes gap"
(/ (car time) (* .01 (cdr time)))
(car time)
(cdr time)
(- (cdr time) (car time)))))
(defun sacha/org-load (match)
"Can be included in `org-agenda-custom-commands'."
(let ((inhibit-read-only t)
(time (sacha/org-calculate-free-time
;; today
(calendar-gregorian-from-absolute org-starting-day)
;; now if today, else start of day
(if (= org-starting-day
(time-to-days (current-time)))
(let* ((now (decode-time))
(cur-hour (nth 2 now))
(cur-min (nth 1 now)))
(+ (* cur-hour 60) cur-min))
(let ((start (car (elt org-agenda-time-grid 2))))
(+ (* (/ start 100) 60) (% start 100))))
;; until the last time in my time grid
(let ((last (car (last (elt org-agenda-time-grid 2)))))
(+ (* (/ last 100) 60) (% last 100))))))
(goto-char (point-max))
(insert (format
"%.1f%% load: %d minutes to be scheduled, %d minutes free, %d minutes gap"
(/ (car time) (* .01 (cdr time)))
(car time)
(cdr time)
(- (cdr time) (car time))))))
(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 ((files org-agenda-files)
(total-unscheduled 0)
(total-gap 0)
file
rtn
rtnall
entry
(last-timestamp start-time)
scheduled-entries)
(while (setq file (car files))
(catch 'nextfile
(org-check-agenda-file file)
(setq rtn (org-agenda-get-day-entries file date :scheduled :timestamp))
(setq rtnall (append rtnall rtn)))
(setq files (cdr files)))
;; For each item on the list
(while (setq entry (car rtnall))
(let ((time (get-text-property 1 'time entry)))
(cond
((and time (string-match "\\([^-]+\\)-\\([^-]+\\)" time))
(setq scheduled-entries (cons (cons
(save-match-data (appt-convert-time (match-string 1 time)))
(save-match-data (appt-convert-time (match-string 2 time))))
scheduled-entries)))
((and time
(string-match "\\([^-]+\\)\\.+" time)
(string-match "^[A-Z]+ \\([0-9]+\\)" (get-text-property 1 'txt entry)))
(setq scheduled-entries
(let ((start (and (string-match "\\([^-]+\\)\\.+" time)
(appt-convert-time (match-string 1 time)))))
(cons (cons start
(and (string-match "^[A-Z]+ \\([0-9]+\\)" (get-text-property 1 'txt entry))
(+ start (string-to-number (match-string 1 (get-text-property 1 'txt entry))))))
scheduled-entries))))
((string-match "^[A-Z]+ \\([0-9]+\\)" (get-text-property 1 'txt entry))
(setq total-unscheduled (+ (string-to-number
(match-string 1 (get-text-property 1 'txt entry)))
total-unscheduled)))))
(setq rtnall (cdr rtnall)))
;; 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))))
Random Emacs symbol: select-safe-coding-system-function – Variable: Function to call to select safe coding system for encoding a text.