Fork me on Github

klog

klog is a plain-text file format and a command line tool for time tracking. It is free and open-source software distributed under the MIT License.

Get the latest version of klog here: github.com/jotaen/klog

Introduction

The idea behind klog is to store data in plain-text files in a simple and human-readable format. The notation is similar to how you would write down the information into a physical notebook using pen and paper. Manipulating your data is as easy as opening the file in a text editor and making changes to the text. By using the klog command line tool you can search, evaluate and manipulate your data from the terminal.

Screen recording of the demo described below

Let’s say you started a new job and want to use klog for tracking work times:

2018-03-24
First day at my new job
8:30 - 17:00
-45m Lunch break

At the 24th of March 2018 you came to the office at 8:30 in the morning and went home at 17:00 in the afternoon. Somewhere in between there was a 45-minute lunch break.

As you see, klog supports different notations to record times. You can capture short summaries about your activities along with the time data (only if you want, of course), which can help you later on to make sense of what you did back in the day. And by adding tags you are able to run more fine-granular evaluations.

When stored in a file (e.g. worktimes.klg) you can use the klog command line tool to interact with it. For instance, you could evaluate the resulting total time like this:

klog total worktimes.klg
Total: 7h45m
(In 1 record)

In case you want to add an extra 30 minutes, you can do:

klog track '30m' worktimes.klg

File Format

Version 1 (RFC)

klog is based on plain text files that hold the data. The file extension is .klg.

A .klg file can contain any number of records that each consists of a date, time entries, and (optionally) summary texts.

2018-03-24
First day at my new job
8:30 - 17:00
-45m Lunch break

2018-03-25
8h15m Onboarding and introduction

2018-03-26
Started to work on a first small
project (new sales brochure)
8:50 - 12:45
14:00 - 18:00

Records are separated by one blank line between them. The first line of a record must be a date (formatted either YYYY-MM-DD or YYYY/MM/DD).

Tracking time

Entries are the actual time values that you track. Each entry represents an amount of time that you spent on something. The computed total time of a record is the sum of all its entries.

2019-07-22
1h
8:00 - 9:00

Both entries in this example are worth 1 hour each, resulting in a total time of 2 hours for this day.

Entries appear one per line and are indented by one level. Indentation is either 1 tab or 2–4 spaces. The order of entries can be arbitrary and has no influence on the result. Entries can be:

Summaries

The purpose of summaries is to capture arbitrary information alongside the data for future reference.

2020-02-18
Woke up this morning with the plan
to make the world a better place
10h Watched movies

Summaries are optional and can appear:

Tagging / categorising

Summaries can contain #hashtags that allow for more fine-granular filtering of the data later on.

2019-07-22
Did some #sports
2h #badminton session with Max
1h Went out for a #run

If a tag appears in the overall record summary, then all entries will match when filtering for that tag. If a tag appears in an entry summary, only the respective entry will match.

In this example, the total time for the tag #sports would be 3h, and the total time for #run would be 1h.

Open-ended time ranges

In case you just begin an activity (without knowing when it will end) you can already log it in your file as an open-ended time range.

2019-07-26
Started to read my new book
16:30 - ?

Open-ended time ranges are denoted by replacing the end time with a question mark, otherwise they work the same as normal entries. Note that there can only be one open-ended range per record, and it doesn’t count towards the total time as long as it’s open.

Should-total

There are use-cases where you have a certain overall time goal that you want to achieve. This so-called should-total property can appear after the record’s date, surrounded by parentheses. It is a duration value followed by an exclamation mark. For example, let’s say you are supposed to work 7½ hours per day:

2019-07-26 (7h30m!)
8:00 - 16:00 Work
-45m Lunch break

Should-totals are a meta-property that can be useful for evaluation purposes, e.g. when you want to diff actual times against your designated goal. The should-total always applies to the entire record with all its entries.

Day shifting

Sometimes you start an activity in the evening and end it after midnight, just so that start and end time don’t belong to the same calendar date. For this case it is possible to “shift over” a time to the previous or to the next day by adding the < prefix, or the > suffix respectively.

2019-07-26
<23:30 - 8:00 Worked a night shift
22:30 - 1:45> Watched some movies

When filtering records, keep in mind that these entries are still associated with the date they are recorded under, so the total time for the above date 2019-07-26 is 11h45m. (If there are records for the adjacent days, their total time won’t be affected.)

FAQ

Is it possible to use to-the-second precision, like 1h10m30s or 8:23:49?

No, this is not supported. The reason is that it would effectively prohibit mixing values with and without seconds, which leads to a lot of hassle. Keep in mind, klog is for tracking time of activities, it’s not a stopwatch.

Can I capture timezone information?

No. In case you are affected by a timezone change or a switch to daylight saving time you need to account for that yourself. Realistically, this doesn’t happen all too often anyway, so it’s a tradeoff for simplicity to omit the timezone information altogether.

Can there be multiple records for the same date in one file?

Yes, as many as you want.

Are there any constraints in regards to the way I track times?

klog generally doesn’t impose too many restrictions. Examples of things that are allowed: tracking more than 24h per day; tracking only negative durations; time ranges that overlap; negative should-total values; empty records (that don’t contain any entries).
There might be valid reasons for such use cases, so klog deliberately is not stricter than necessary.
What the command line tool does do, however, is to raise warnings about certain potential issues, for example when it detects an open time range at a past date.

Specification

You find the formal specification of the file format in the repository.

Command line tool

v2.2

The command line tool allows you to find and filter records in files, pretty print and evaluate them, and apply some basic manipulations. The following sections demonstrate the usage of the subcommands. (They are not a complete reference, though.) In order to learn about all flags and options please run klog with the --help flag (which is also available on the subcommands).

In case there are syntax errors in the input text, klog cannot process it and displays an error message instead, which hopefully helps you fix the problem. Also some commands emit warnings to draw your attention to potential logical issues in your data.

For the evaluation commands you can specify input in one of the following ways:

Pro-tip: most shells have native support for glob patterns, so in case you want to organise your records throughout multiple files (e.g. one file per month) you can process them all at once by passing the glob pattern *.klg.

print

With the print subcommand you can pretty-print one or multiple files onto the terminal. You can apply filters in case you look for something specific. Printing is a good way to double-check that the syntax in a file is all correct.

klog print worktimes.klg

total

The total subcommand evaluates the total time of the records from one or more files.

klog total sport.klg

If you want to evaluate all records in sport.klg since January 2018 that are tagged with #workout, you would do:

klog total --since=2018-01-01 --tag=workout sport.klg

Note that open time ranges are not taken into account by default. You can factor them in by passing the --now flag.

klog total --now sport.klg

report

Prints a report of the records as a timeline (like in a calendar), listing all days and their total times.

klog report 2020.klg

Use with the --fill option to print a consecutive stream of all dates.

tags

Displays an overview of all available tags and the aggregated total time for each of them.

klog tags sports.klg

now

Displays a side-by-side view of the most recent record (either today or yesterday) and the overall statistics, similar to klog total --now.

klog now sports.klg

In case you have should-totals set this will also calculate the E.T.A. (the “estimated time of arrival”, i.e. at which time your goal will be reached). By using the --follow flag you can keep the shell process open to display live updates.

track

Add a new entry to an existing record:

klog track '1h30m' sports.klg

If you don’t specify a date then klog will look for a record at today’s date. Say, today was the 14th of February 2012, then the above example command would append a new entry so that the resulting record would look like this:

2012-02-14
8:15 - 9:45 Morning run
1h30m

You can not just track time values that way, but you can also add the summary text right away. (Effectively, the argument is just the entire entry line as it is supposed to appear in the record.)

klog track '8:00-16:00 Workday' work.klg

Note that you should wrap the value into single quotes in order for your shell to treat it as single argument and to avoid special characters to be interpreted. In case you want to track a negative duration please remember to escape the leading minus with two backslashes:

klog track '\\-30m Coffee break' work.klg

start

Starts a new open-ended time range:

klog start work.klg

The command expects a record to be present at the current date. You can also specify a date explicitly through the --date flag.

By default the current time is used as start time. You can optionally specify it with the --time 5:00 flag. If you want, you can use the alias klog in.

stop

Stops an ongoing open-ended time range:

klog stop work.klg

Otherwise it works in the same way as klog start does.

create

Creates a new record:

klog create reading.klg

By default the current day is used as date. You can also specify a date explicitly via the --date flag. The command assumes the records in the file to be in chronological order and inserts it at the right position. You can pass a should-total property with the --should flag.

bookmark

Configure a default file for klog to read from:

klog bookmark set my-current-file.klg

When a bookmark is set, you don’t have to specify an input file for the subcommands anymore. (You are still able to, though.) Bookmarking is a useful convenience so that you don’t have to browse to a specific working directory all the time. Instead, you can interact with your bookmark from any location:

klog total --today

You can also quickly open up the bookmark in your favourite editor (based on the $EDITOR environment variable).

klog bookmark edit

json

Converts records into a JSON data structure that allows you to process the data by means of other tools or scripts programmatically.

klog json somefile.klg

The output structure is not explicitly documented yet. Run it with the --pretty flag in order to explore the output structure, it should be largely self-explanatory.

Remember that klog checks stdin for input as well, which might be handy when you invoke it as subprocess from another program.

widget (MacOS only)

On MacOS there is an experimental menu bar (systray) widget bundled into the command line tool. It displays an ongoing counter of the current day and the statistics of a file. As source file the bookmark is being used. You can launch the widget by running:

klog widget

Use the --detach option to run the widget standalone (detached from the shell process).

version

Displays which version of the command line tool you are on. This also checks online whether there is a new version available.

klog version

Extensions

This is an ongoing collection of all kinds of extensions around klog. If you have built a utility for klog, please open an issue so that it can be added to this list.
In case you need the klog logo for anything, see here.

VSCode

Editor plugin for VSCode for syntax-highlighting and snippets.
See: github.com/vladdeSV/vscode-klog
(Maintained by @vladdeSV)