TaskWarrior, TimeWarrior, and that moment it all goes wrong

I've been a user of TaskWarrior for a long time, though not always seriously, and I recently started using TimeWarrior with it so that I can keep track of the time that I spend on tasks. This is a tale about how it all went wrong, but because of some really smart choices by the original developers, it all came back in the end.

I work for an agency, so time tracking is super important for us. We do some crazy things, like having our task list based on a Google Sheet, so I've got some convoluted scripts that run and pull those tasks in to TaskWarrior (if you're interested in the source, message me somewhere). I've got on-modify.timewarrior as one of the hooks on TaskWarrior (though I've modified it to only use the uuid of the task in the TimeWarrior store), and have been happily tracking my time that way for about a week now.

Today though, I needed to track time for a task that wasn't part of my existing task list, and getting a new task would have taken longer than the actual doing of the task took in the first place, so I decided to simply track the time in TimeWarrior manually. I didn't actually start the TimeWarrior tracking until after the task was finished, which is where things start going wrong.

If you run a command like this timew start 1h ago 'this is my task', and there's already time that's been logged during that previous timeframe, TimeWarrior will helpfully tell you that you can't overlap times in this way, but that you can do so if you pass in :adjust to the command. Cool, I thought. I started this task half an hour ago, so I'll timew start 30m ago 'this is my task' :adjust. Here, things have officially gone wrong. In TimeWarrior, minutes are specified with mins, and months are specified with m. I'd told TimeWarrior to start this task thirty months ago, and it proceeded to write out all of the information to it's monthly tracking files, in the process overwriting the time that I'd tracked over the last week, sending me in to a mild panic.

Luckily, Paul and crew with TaskWarrior/TimeWarrior have an undo.data file that sits along with the monthly data files. TimeWarrior doesn't currently (as of 1.1.1) have an undo command, but using the undo.data file and a little bit of shell magic, I was able to regenerate the monthly data file to get what I needed. I can all but guarantee that the devs will say that this is an incorrect way to do this (it absolutely is, but in a pinch, it did what I needed), but I'll share the shell script here in case it might help someone else in their moment of need. It requires jq, which is yet another amazing tool that everyone should attempt to learn, but that's another post.

Here's the script. It's rather short, and probably doesn't handle some edge-cases (for example, if you use more than one tag in your TimeWarrior data), but it worked for my use case. If you want to suggest improvements, please message me on Twitter or anywhere else you can figure out how to reach me.

grep 'start' undo.data | grep end | grep after | sed -e 's/after: //;' | jq -r '"inc "+.start+" - "+.end+" # \""+.tags[0]+"\""' >> 2018-12.data