Hello everyone, I was thinking that it would be nice to have a visual representation of clocked time. It could give you a quick overview of when and how long you had been working on a particular task.
For example, you have a subtree like this: ** very important task CLOCK: [2009-10-03 Sat 22:02]--[2009-10-03 Sat 23:21] => 1:19 CLOCK: [2009-10-04 Sun 23:53]--[2009-10-05 Mon 02:10] => 2:17 CLOCK: [2009-10-06 Tue 14:10]--[2009-10-06 Tue 14:50] => 0:40 CLOCK: [2009-10-07 Wed 21:25]--[2009-10-08 Thu 00:21] => 2:56 CLOCK: [2009-10-13 Tue 01:52]--[2009-10-13 Tue 02:52] => 1:00 CLOCK: [2009-10-13 Tue 20:58]--[2009-10-13 Tue 23:32] => 2:34 CLOCK: [2009-10-14 Wed 23:20]--[2009-10-15 Thu 00:55] => 1:35 CLOCK: [2009-10-16 Fri 14:14]--[2009-10-16 Fri 14:53] => 0:39 some text here You press a combination of keys and get a table like this: |---------------+-----+-----+-----+-----+-----+-----+-----+------| | Week Starting | Mon | Tue | Wed | Thu | Fri | Sat | Sun | tt,h | |---------------+-----+-----+-----+-----+-----+-----+-----+------| | 2009-09-28 | | | | | | 79 | 137 | 3.6 | | 2009-10-05 | | 40 | 176 | | | | | 3.6 | | 2009-10-12 | | 214 | 95 | | 39 | | | 5.8 | |---------------+-----+-----+-----+-----+-----+-----+-----+------| The table contains total number of clocked minutes for every day and total number of hours for every week. If I could write such a thing in Emacs lisp, I would do that. But unfortunately I can't. So, I wrote a python script and small function in lisp to call it. I am posting them here in hope that it might be useful for someone. Org-mode is an excellent thing. Thank you! Best regards, Gennady Trafimenkov ============================================================ === === ============================================================ (defun gt/org-get-clocked-time-stat-on-subtree () "Calculate nice table with statistics of clocked time. It puts results into buffer '*clocked-time-stat*'. When called with C-u, it copies results into the kill ring. GNU General Public License version 3 or later." (interactive) (let ((outputbuffer "*clocked-time-stat*")) (save-excursion (outline-mark-subtree) (shell-command-on-region (region-beginning) (region-end) "python ~/bin/create-clock-table.py" outputbuffer) (if (equal current-prefix-arg '(4)) (if (get-buffer outputbuffer) (progn (with-current-buffer outputbuffer (mark-whole-buffer) (kill-new (filter-buffer-substring (region-beginning) (region-end)))))))))) ============================================================ === create-clock-table.py ================================== ============================================================ #/usr/bin/env python # # GNU General Public License version 3 or later # # This script extracts all record of this kind from the standart input: # # CLOCK: [2009-10-17 Sat 21:47]--[2009-10-17 Sat 23:10] => 1:23 # # then aggregates data and build table with statistics like this: # |---------------+-----+-----+-----+-----+-----+-----+-----+------| # | Week Starting | Mon | Tue | Wed | Thu | Fri | Sat | Sun | Tot. | # |---------------+-----+-----+-----+-----+-----+-----+-----+------| # | 2009-08-03 | | | | | | | | 0 | # | 2009-08-10 | | | | | | | | 0 | # | 2009-08-17 | | | | 75 | 60 | 60 | 15 | 210 | # | 2009-08-24 | 75 | 60 | 60 | 70 | | | | 265 | # | 2009-08-31 | | 10 | | | | | | 10 | # |---------------+-----+-----+-----+-----+-----+-----+-----+------| import sys import re import datetime if __name__ == '__main__': dailyStat = {} # we are going to extract records like: # CLOCK: [2009-10-17 Sat 21:47]--[2009-10-17 Sat 23:10] => 1:23 timeExtractor = re.compile('^\s*CLOCK: \[(\d{4})-(\d\d)-(\d\d).*\]--\[.*\] =>\s+(\d+):(\d\d)') for line in sys.stdin.readlines(): match = timeExtractor.match(line) if match: year, month, day = int(match.group(1)), int(match.group(2)), int(match.group(3)) hours, minutes = int(match.group(4)), int(match.group(5)) date = datetime.date(year, month, day) minutes += hours * 60 # print date, minutes dailyStat.setdefault(date, 0) dailyStat[date] += minutes if len(dailyStat) == 0: sys.exit(0) minDate = min(dailyStat.keys()) maxDate = max(dailyStat.keys()) firstWeek = minDate - datetime.timedelta(minDate.weekday()) lastWeek = maxDate - datetime.timedelta(maxDate.weekday()) # calculate weekly stat ############################################################ weeklyStat = {} week = firstWeek while week <= lastWeek: weeklyStat[week] = [0, 0, 0, 0, 0, 0, 0, 0] week += datetime.timedelta(7) biggestNumber = 0 for day in dailyStat.keys(): weekday = day.weekday() week = day - datetime.timedelta(weekday) weeklyStat[week][weekday] = dailyStat[day] weeklyStat[week][7] += dailyStat[day] biggestNumber = max(biggestNumber, dailyStat[day]) def PrintTableLine(firstColumn, otherColumns, otherColumnsWidth): cellTemplate = " %%%ds |" % otherColumnsWidth line = "| %13s |" % firstColumn for i in otherColumns: if i == 0: line += cellTemplate % "" else: line += cellTemplate % i print line def PrintTableDelimiter(numOfColumns, otherColumnsWidth): column = "-" * (otherColumnsWidth + 2) line = "|" + "-" * (13 + 2) for i in xrange(1, numOfColumns+1): line += "+" line += column line += "|" print line # printing the weekly stat table ############################################################ columnWidth = max(4, len("%d" % biggestNumber) + 1) PrintTableDelimiter(8, columnWidth) PrintTableLine("Week Starting", ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun", "tt,h"], columnWidth) PrintTableDelimiter(8, columnWidth) cellTemplate = " %%%ds |" % columnWidth week = firstWeek while week <= lastWeek: # convert total number of minutes in number of hours weeklyStat[week][7] = "%0.1f" % (float(weeklyStat[week][7]) / 60) PrintTableLine(week.isoformat(), weeklyStat[week], columnWidth) week += datetime.timedelta(7) PrintTableDelimiter(8, columnWidth) ============================================================ _______________________________________________ Emacs-orgmode mailing list Remember: use `Reply All' to send replies to the list. Emacs-orgmode@gnu.org http://lists.gnu.org/mailman/listinfo/emacs-orgmode