How I track my time with Org document and a couple of Perl scripts

Many of you track time when you work on the computer, either to bill your client or just to find out how long you have worked so you can track/summarize your progress. There are various ways to do this. This article will describe my own particular way which I have been using for almost 2 years. I hope you'll find it useful. Comments and suggestions are very welcome.

Before discussing my solution, let's consider some of the alternatives. First there is the CPAN module App::TimeTracker. It is a command-line application. To use it, first cd to your project directory and type tracker init. This will create a .tracker.json configuration file. Then you type tracker start when you start work on a project and tracker stop when you finish working. The timers are stored JSON record files in $HOME/.TimeTracker/YYYY/*.trc files such as this:

{
"duration" : "00:00:55",
"start" : "2014-01-28T19:10:39",
"tags" : [],
"user" : "u1",
"__CLASS__" : "App::TimeTracker::Data::Task",
"project" : "myproj",
"stop" : "2014-01-28T19:11:34",
"seconds" : 55
}

For report, use tracker report. Sample output:

From 2014-01-01T00:00:00 to 2014-01-28T19:24:33 you worked on:
myproj 00:12:45
total 00:12:45

Another alternative is Emacs' org-mode which has a clock feature. First you list the tasks and subtasks as headlines:

* proj 1
** subproj 1.1
** subproj 1.2
* proj 2

then to start working on a project, you press C-c C-x C-i (/Ctrl-cxi/). A "CLOCK" and a timestamp will be shown. To stop the clock, press Ctrl-cxo and the timestamp will be completed and becomes a timerange. There can only be one active clock running, so you can just press Ctrl-cxi on another project and the previous clock will be stopped and the new one started. An example of resulting document after several starts and stops:

* proj 1
CLOCK: [2014-01-28 Tue 19:29]--[2014-01-28 Tue 19:30] => 0:01
CLOCK: [2014-01-28 Tue 19:27]--[2014-01-28 Tue 19:28] => 0:01
** subproj 1.1
CLOCK: [2014-01-28 Tue 19:30]
** subproj 1.2
* proj 2
CLOCK: [2014-01-28 Tue 19:28]--[2014-01-28 Tue 19:28] => 0:00

To view the report, press Ctrl-cxr. This will insert a dynamic block like this:

#+BEGIN: clocktable :maxlevel 2 :scope file
Clock summary at [2014-01-28 Tue 19:42]

| L | Headline | Time |
|---+--------------+--------|
| | *Total time* | *0:02* |
|---+--------------+--------|
| 1 | proj 1 | 0:02 |
#+END:

Now I'll describe my homegrown method. First of all, I like using a text editor for keeping the time because of the way I work. Often I'll start a timer but then a couple of minutes later got distracted to working on another project so the first project never actually got started being worked on. Or perhaps during a couple of hours of working I got interrupted (or distracted) multiple times by phone calls, instant messages, coworkers so I would want to subtract some amount of time. If I use an editor, like in org-mode clocks, I can just undo or edit the timestamps directly. Not so convenient with App::TimeTracker.

Next, I want a nice format. The Org timestamps looks too verbose to my eyes, so here's a format I ended up with. Below is a snippet of document I call daily.org:

* [2014-01-27 Mon] (+04:19) laa, orgtovcf
- 08:21-09:21 = (coding) laa: continue add filter
- 12:56-16:15 = (coding) orgtovcf: continue creating first version
* [2014-01-26 Sun] (+01:46) orgtovcf, laa
- 12:22-13:02 -00:10 14:27-14:37 = (coding) orgtovcf: continue creating first
version
- 14:45-15:51 = (coding) laa: add filter

With this format, each working day is put in a single headline with a timestamp. Inside the headline there is a list with each list item containing activities and projects. That's the next thing I want: separation between projects and activities. For a Perl module project, as an example, there can be a coding, documenting, debugging. Another example, on a project called langlearn
(for "language learning") I can have the activity of writing, listening, reading, and speaking.

Now here's the thing: I currently write most of the contents in the file manually, because as I explained before, I often need to edit the times. At the start of a new day I first write (note that timestamp can be inserted in Emacs using C-c !):

* [2014-01-26 Sun] () ...

The () will be filled with the total amount of time I'll be working that day (which can be calculated manually or with the help of a script, more on that later). The ... part can be filled with a summary text. I usually write 1-2 projects which I work the most that day. This will give a nice summary when the days headlines are collapsed:

* [2013-11-30 Sat] (+01:17) notes, perl
* [2013-11-29 Fri] (+06:30) App-Riap, notes
* [2013-11-28 Thu] (+01:21) finance
* [2013-11-27 Wed] (+05:59) App-Riap

To start working on a project (for example I plan to code on a Perl module), I look at the clock and type under the day headline:

- 08:11- = (coding) Foo-Bar: add a baz feature

Later when I stop working:

- 08:11-09:12 = (coding) Foo-Bar: add a baz feature

For a single project/activity, I can spend multiple time blocks on it (~-hh:mm~ means subtract an amount of time, +hh:mm means add an amount of time):

- 12:22-13:02 -00:10 14:27-14:37 = (coding) orgtovcf: continue creating first
version

I like the flexibility of specifying times like this.

Now back to the () in the day headline. To calculate the daily total, I use a Perl script called fill-in-daily-totals. To do this in Emacs, I select the day(s) as a region, then type C-u M-| fill-in-daily-totals RET. This will filter the region through the script. The script will insert the times, so this:

* [2014-01-26 Sun] () blah
- 08:11-09:12 = (coding) Foo-Bar: add a baz feature
* [2014-01-25 Sat] () blah blah
- +02:00 = (coding) proj1: blah
- 09:10-11:45 -00:15 = (writing) writings: write article Foo

will become this:

* [2014-01-26 Sun] (+01:01) blah
- 08:11-09:12 = (coding) Foo-Bar: add a baz feature
* [2014-01-25 Sat] (+04:20) blah blah
- +02:00 = (coding) proj1: blah
- 09:10-11:45 -00:15 = (writing) writings: write article Foo

To create weekly summary, I wrote gen-weekly-work-summary. I collect the output of this script to an Org file called weekly.org. Example output (sometimes I put additional notes to this file):

** [2013-12-15 Sun] (+26:27) perl releases=17 ( 2 new,  0 non-cpan)
- some additional notes: blah...
- top 3 projects: perl, mkey, notes
- breakdown per project:
.-----------+--------------.
| project | duration |
+-----------+--------------+
| perl | +19:48 (75%) |
| mkey | +02:39 (10%) |
| notes | +00:49 (3%) |
| app-riap | +00:47 (3%) |
| personal | +00:45 (3%) |
| shroles | +00:34 (2%) |
| finance | +00:33 (2%) |
| mwn | +00:20 (1%) |
| organizer | +00:12 (1%) |
`-----------+--------------'
- breakdown per activity:
.-----------+--------------.
| activity | duration |
+-----------+--------------+
| coding | +23:48 (90%) |
| noting | +01:34 (6%) |
| admin | +00:45 (3%) |
| mentoring | +00:20 (1%) |
`-----------+--------------'

So far I jot notes for monthly.org, quarterly.org, and yearly.org manually for now, by looking at and summarizing weekly summaries in weekly.org.

To sum up: I like the format I'm using because: 1) it's manual enough so it's very flexible; 2) it's easy to visually see daily summaries in Emacs (org-mode); 3) I can create weekly summaries (and later monthly/quarterly/yearly, if needed) and see a breakdown of activities and projects.

The scripts mentioned in this article are included in Perl distribution SHARYANTO-TimeSheet-Parser which I haven't put on CPAN yet. It's on my personal "DarkPAN": https://github.com/sharyanto/darkpan-steven and can be installed using something like:

% cpanm -n --mirror https://github.com/sharyanto/darkpan-steven/raw/master \
--mirror http://www.cpan.org/ \
--mirror-only \
SHARYANTO::TimeSheet::Parser

3 Comments

You might also check out the app my wife and I use: https://metacpan.org/pod/App::JobLog. I think there might be someone else out there who uses it too. Anyway it's an alternative.

Hmm... I thought I left a comment here but now I don't see it. Anyway, you might check out App::JobLog. Full disclosure: I wrote it.

Leave a comment

About Steven Haryanto

user-pic A programmer (mostly Perl 5 nowadays). My CPAN ID: SHARYANTO. I'm sedusedan on perlmonks. My twitter is stevenharyanto (but I don't tweet much). Follow me on github: sharyanto.