Time tracking with Ledger

Whoever is reading this blog knows that I use Ledger-likes to track my finances. Some of you may also know that the currency is just some arbitrary name for any kind of unit. And a minority of you may also know there is special support for tracking time in the original Ledger program. This post explains how I use Ledger and a few Bash aliases to track different activities during a normal work day.

In a “regular” Ledger file you will find transactions that describe the flow of a commodity from one (or more) to another account at a certain time. There is however special support for timelog entries in the ledger program. They look similar but have special syntax to describe the start and end of a “transaction”

i 2019/03/02 00:30:20 Entertainment:Netflix
o 2019/03/02 00:35:20

which basically state what to account from i to o. Suppose you have a timelog file foo.ledger then ledger -f time.ledger bal would give you something like this:

               9.07h Work
               32.3m    Mail
                6.9m    Admin
               8.40h    Development
               1.69h Entertainment:Netflix
               14.2m Drinking
               11.9m Meetings
--------------------
               11.19h

Of course, you can customize the date range and hierarchy depth. Let’s alias that to

alias wasted='ledger -f ${TIMELOG} bal -b $(date -dlast-monday +%m/%d) --depth 2'

All good. Now, adding new entries by “punching in” new lines like that above is more than just cumbersome, it’s something a simple alias could do as well. I have defined something like

alias clock-in='echo i $(date +"%Y/%m/%d %H:%M:%S") >> ${TIMELOG}'
alias clock-out='echo o $(date +"%Y/%m/%d %H:%M:%S") >> ${TIMELOG}'

where TIMELOG points to the time.ledger file. Once you type

$ clock-in Work:Mail

an appropriate transaction will be made. To check what’s currently going on, this alias might help:

alias clock-status='[[ $(tail -1 ${TIMELOG} | cut -c 1) == "i" ]] && { echo "Clocked IN to $(tail -1 ${TIMELOG} | cut -d " " -f 4)"; wasted; } || { echo "Clocked OUT"; wasted;}' 

That all looks nice and dandy until you realize you don’t remember a particular activity you want to account you current time on. If you have used any CLI program you probably hit Tab more than twice. Wait no more, just define


function _clock_in ()
{
    local cur prev
    _get_comp_words_by_ref -n : cur

    local words="$(cut -d ' ' -s -f 4 ${TIMELOG} | sed '/^$/d' | sort | uniq)"
    COMPREPLY=($(compgen -W "${words}" -- ${cur}))
    __ltrim_colon_completions "${cur}"
}

complete -F _clock_in clock-in

and you are all set to complete the timelog entry while you clock in. You could write more elaborate logic in an appropriate scripting language but that’s an exercise for the reader.