emacs-orgmode@gnu.org archives
 help / color / mirror / code / Atom feed
* Visual representation of clocked time
@ 2009-11-02 21:16 Gennady Trafimenkov
  2009-11-03 17:03 ` Carsten Dominik
  0 siblings, 1 reply; 2+ messages in thread
From: Gennady Trafimenkov @ 2009-11-02 21:16 UTC (permalink / raw)
  To: emacs-orgmode

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)

============================================================

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: Visual representation of clocked time
  2009-11-02 21:16 Visual representation of clocked time Gennady Trafimenkov
@ 2009-11-03 17:03 ` Carsten Dominik
  0 siblings, 0 replies; 2+ messages in thread
From: Carsten Dominik @ 2009-11-03 17:03 UTC (permalink / raw)
  To: Gennady Trafimenkov; +Cc: emacs-orgmode

Hi Gennady,

thanks for sharing!

- Carsten

On Nov 2, 2009, at 10:16 PM, Gennady Trafimenkov wrote:

> 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

- Carsten

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2009-11-03 17:46 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-11-02 21:16 Visual representation of clocked time Gennady Trafimenkov
2009-11-03 17:03 ` Carsten Dominik

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).