A command line time tracking application. Docs at https://tiempo.categulario.xyz
Go to file
Abraham Toriz 62d432b5ba
Fixed dependencies and description in AUR packages
2022-07-24 22:31:49 +08:00
assets add files for the logo 2021-12-13 23:31:01 -06:00
completions/bash autocomplete sheet names in t k 2021-07-30 17:54:35 -05:00
docs Traducción al español y corrección de erratitas al inglés 2021-12-03 01:31:59 +00:00
scripts use correct dependencies and description in AUR deployments 2022-07-24 22:31:20 +08:00
src fix clippy lint 2022-07-21 22:04:25 +08:00
.gitignore add docs structure for en and es 2021-10-26 20:16:30 -05:00
.gitlab-ci.yml Now release to AUR as -git 2022-07-22 18:49:32 +08:00
CHANGELOG.md Upgrade rusqlite to 0.28 and fix aur -git release 2022-07-22 19:23:59 +08:00
Cargo.lock Fixed dependencies and description in AUR packages 2022-07-24 22:31:49 +08:00
Cargo.toml Fixed dependencies and description in AUR packages 2022-07-24 22:31:49 +08:00
LICENSE the complete CI infra 2021-12-03 09:59:49 -06:00
README.md fix typo 2022-07-22 20:17:42 +08:00
debpackage.sh the complete CI infra 2021-12-03 09:59:49 -06:00

README.md

Tiempo

A timetrap compatible command line time tracking application.

Installation

For Archlinux (and derivatives) users

There are a binary and a source package in the AUR:

For every other linux users

Go to gitlab releases page and grab the latest binary for your linux. There is a .deb file for Debian and Ubuntu as well as a binary for any x86_64 Linux.

For Rust developers

You have cargo! you can run:

cargo install tiempo

For everyone else

You need to compile tiempo by yourself. But don't worry! It is not that hard. Just clone the repository, make sure you have rust installed and run:

cargo build --release

inside the repository. The binary will be named t (or t.exe if you use windows) and it is located inside the target/release directory that was created during compilation.

Tutorial

First of all, you can abbreviate all commands to their first letter, so t in and t i are equivalent.

Managing entries

Register the start of an activity in the default timesheet with:

t in 'Doing some coding'

which sets the activity's start time to the current time. Later when you're done use

t out

to mark it as finished. If you forgot to start the activity before you can do so with:

t i --at '20 min ago'

the same applies for t out.

Edit an entry with

t edit [options]

where the options are

-i, --id <id:i>           Alter entry with id <id> instead of the running entry
-s, --start <time:qs>     Change the start time to <time>
-e, --end <time:qs>       Change the end time to <time>
-a, --append              Append to the current note instead of replacing it
                          the delimiter between appended notes is
                          configurable (see configure)
-m, --move <sheet>        Move to another sheet

You can remove an entry with

t kill --id 123

or an entire timesheet with

t kill somesheet

check bellow to see how to get the ids.

Displaying entries

At any point in time you can check your time spent in the current or other timesheet with:

t display [options] [SHEET | all | full]

the available options are

-v, --ids                 Print database ids (for use with edit)
-s, --start <date:qs>     Include entries that start on this date or later
-e, --end <date:qs>       Include entries that start on this date or earlier
-f, --format <format>     The output format.  Valid built-in formats are
                          ical, csv, json, ids, factor, and text (default).
                          Check the docs on defining custom formats bellow.
-g, --grep <regexp>       Include entries where the note matches this regexp

Some shortcuts available are:

today - Display entries that started today

t today [--ids] [--format FMT] [SHEET | all]

yesterday - Display entries that started yesterday

t yesterday [--ids] [--format FMT] [SHEET | all]

week - Entries of this week so far. The default start of the week is Monday (configurable).

t week [--ids] [--end DATE] [--format FMT] [SHEET | all]

month - Entries of this month or a specified one.

t month [--ids] [--start MONTH] [--format FMT] [SHEET | all]

Using different timesheets

You can organize your activities in different timesheets by first switching to an existing one, then starting an activity:

t sheet somename
t in 'some activity'

which will also create the timesheet if it doesn't exist.

List all existing timesheets using

t list [all]

(defaults to not showing archive timesheets with names preceded by an underscore)

Advanced management

You can archive entries from a timesheet using:

t archive [--start DATE] [--end DATE] [SHEET]

which defaults to archiving all entries in the current sheet, or you can be more specific using these options:

-s, --start <date:qs>     Include entries that start on this date or later
-e, --end <date:qs>       Include entries that start on this date or earlier
-g, --grep <regexp>       Include entries where the note matches this regexp.

This subcommand will move the selected entries to a hidden timesheet named _[SHEET] (the name of the timesheet preceded by an underscore).

It is possible to access directly the sqlite database using

t backend

Configuration

tiempo keeps a config file, whose location you can learn usign t configure. It is also possible to edit the config file in-place passing arguments to t configure like this:

t c --append-notes-delimiter ';'

it will print the resulting config file. Beware that it wont keep comments added to the file.

Specifying times

Some arguments accept a time as value, like t in's --at or t d --start. These are the accepted formats:

Something similar to ISO format will be parsed as a time in the computer's timezone.

  • 2021-01-13 a date
  • 2019-05-03 11:13 a date with portions of a time

ISO format with offset or UTC will be parsed as a time in the specified timezone. Use Z for UTC and an offset for everything else

  • 2021-01-13Z
  • 2005-10-14 19:20:35+05:00

something that looks like an hour will be parsed as a time in the current day in the computer's timezone. Add Z or an offset to specify the timezone.

  • 11:30
  • 23:50:45 (with seconds)

some human times, for now restricted to time ago:

  • an hour ago
  • a minute ago
  • 50 min ago
  • 1h30m ago
  • two hours thirty minutes ago

Custom formatters

You can implement your own formatters for all subcommands that display entries (like t display, t week etc.). It is as easy as creating an executable file written in any programming language (interpreted or compiled) and placing it in a path listed in the config value for formatter_search_paths.

This executable will be given as standard input a csv stream with each row representing a time entry with the same structure as the csv formatter output. It will also be given a command line argument representing user settings for this formatter stored in the config file and formatted as JSON.

Example

Suppose we have this config file:

database_file = "/home/user/.config/tiempo/database.sqlite3"
round_in_seconds = 900
append_notes_delimiter = " "
formatter_search_paths = ["/home/user/.config/tiempo/formatters"]
default_formatter = "text"
auto_sheet = "dotfiles"
auto_sheet_search_paths = ["/home/user/.config/tiempo/auto_sheets"]
auto_checkout = false
require_note = true
week_start = "Monday"

[formatters.earnings]
hourly_rate = 300
currency = "USD"

then we can create the earnings formatter by placing the following file in /home/user/.config/tiempo/formatters/earnings:

#!/usr/bin/env python3
import sys
import json
import csv
from datetime import datetime, timezone
from datetime import timedelta
from math import ceil

config = json.loads(sys.argv[1])

reader = csv.DictReader(
    sys.stdin,
    fieldnames=['id', 'start', 'end', 'note', 'sheet'],
)

total = timedelta(seconds=0)

for line in reader:
    start = datetime.strptime(line['start'], '%Y-%m-%dT%H:%M:%S.%fZ')

    if not line['end']:
        end = datetime.utcnow()
    else:
        end = datetime.strptime(line['end'], '%Y-%m-%dT%H:%M:%S.%fZ')

    total += end - start

hours = total.total_seconds() / 3600
earnings = hours * config['hourly_rate']
currency = config['currency']

print(f'You have earned: ${earnings:.2f} {currency}')

Now if you run t display -f earnings you will get something like:

You have earned: 2400 USD

Why did you write this instead of improving timetrap?

  • timetrap is hard to install, hard to keep updated (because of ruby). Once this tool is finished you can get (or build) a binary, put it somewhere, and it will just work forever in that machine. I'm bundling sqlite.
  • timetrap is slow (no way around it, because of ruby), some commands take up to a second. Tiempo always feels snappy.
  • needed major refactor to fix the timezone problem (in a language I'm not proficient with). I was aware of this problem and designed tiempo to store timestamps in UTC while at the same time being able to work with a database made by timetrap without messing up. And there are a lot of tests backing this assertions.

Other advantages

  • Columns in the output are always aligned.
  • Fixed some input inconsistencies.
  • cli interface is easier to discover (ask -h for any sub-command)
  • end times are printed with +1d to indicate that the activity ended the next day in the 'text' formatter.
  • solved some old issues in timetrap.

How to build

You need rust, then clone the repo and simply run

cargo test

to check that everything is working, and then

cargo build --release

to have a binary at target/release/t that you can then move to a directory in your PATH or use it by its absoulte or relative paths.

Run

t --help

to see the options.

Development database

When developing I prefer not to mess with my own database, so I use this .env file:

export TIMETRAP_CONFIG_FILE=/absolute/path/to/repo/dev_config.toml
PS1="$ "

and when I want to test some commands against such config file I just source it:

source .env
cargo run -- in 'hola'

Documentation

The docs are written using sphinx, so first you need to install it somehow. Two options I can offer are:

  • using your computer's package manager. Install a package with a name similar to python-sphinx.
  • using pipenv. Just ensure you have python 3.9 on your computer, enter the docs directory and do pipenv install.

To build the docs just enter the docs directory and some of the language directories (currently es or en) and run:

make html

for the html version (output located at docs/<lang>/build/html), or

make man

for the man page (output located at docs/<lang>/build/man/tiempo.1). If you are using pipenv just prefix the commands with pipenv run or run pipenv shell before running any command.

The contents of the docs are located in docs/<lang>/source/index.rst, formatted as reStructuredText.

Special Thanks

To timetrap for existing, to samg for creating it. It is the tool I was looking for and whose design I took as reference, keeping compatibility when possible.