Command line tool for tracking work time.
I started jobber as a Ruby script in 2013 because in my opinion usual work time tracking tools often come with awful or overloaded UIs. To be more convenient for people who can use a command shell, jobber aims to provide it's functionality by the command line. After 10 years I still find it very useful but although the Ruby script is very handy, it is still full of bugs and just did the minimum job even if it promised much more complex functionality but wasn't able to fulfill it's promises.
In 2021 I started to learn Rust and so I decided to rewrite jobber in that language to get a proper working version that provides all functionality in a sustainable way. After several approaches it turned out that Rust was a good decision because Rust is much more picky about edge cases and has a nice testing environment to prevent any hidden erroneous code which might lead to wrong accounting.
After several month of coding I now can present a first testable version which is not perfect (I still have some more ideas I want to implement) but yet seems more useful and secure than the original Ruby version.
To install jobber you need to install Rust via rustup (see https://rustup.rs) and then use the following line:
txt
▶ cargo install jobber
That's it.
The idea of jobber is that you don't need a UI where you use your mouse or a smartphone touch screen to enter what you did into a form which seemed awful to me most of the time.
So in general the following information must be provided to track your work time:
That's it.
So the basic idea is to provide this in an easy to use command line like this:
txt
jobber -s start_time -e end_time -m message -t tags
Of course it makes sense to start a job and later finish it.
So you can start a job with -s
and finish it later with calling jobber again with -e
.
Also leaving a message often is easier when you know what you have done so you might provide a message when you finish the job - same with the tags.
Providing start and end time would be hard if you have to write done complete date and time every time so you can shorten it to what's necessary like 12:00
for today at noon or just no time to mean right now.
Let's get into an example.
We use the start option -s
to start a new job:
```txt ▶ jobber -s Beginning new database file 'jobber.json' Started new job:
Start: Sat Mar 04 2023, 16:25 End: - open -
Saved database into file 'jobber.json' ```
As you can see jobber tells you that it began with a new database in a file called jobber.json
and has started a new job which end is still open.
It also assures you that changes were written into that file.
If you use a shell which provides color start time will be green and end time will be purple for better reading but in this README which is markdown sadly this can not be visualized.
We can check what we have done by using the list option -l
(see also section List View):
```txt ▶ jobber -l Loaded database (1 entries) from file 'jobber.json' Pos: 1 Start: Sat Mar 04 2023, 16:25 End: - open - Hours: 0.25
Total: 1 job(s), 0.25 hours
Database unchanged. ```
jobber prints out a list of all stored jobs and as you can see there is this one open job we've just started and because some time already elapsed the job hours is given there with a quarter of an hour. By default there is a time resolution of 15 minutes in which work times are calculated. This resolution can be changed but for now we let it to the default.
So let's end the job because let's assume we did something useful and want to finish by using the end option -e
:
```txt ▶ jobber -e Loaded database (1 entries) from file 'jobber.json' You need to enter a message about what you did to finish the job. Finish input with empty line (or Ctrl+C to cancel): Did some nice work
Modified job:
Pos: 1
Start: Sat Mar 04 2023, 16:25 End: Sat Mar 04 2023, 16:34 Hours: 0.15 Message: Did some nice work
Saved database into file 'jobber.json'
```
As you can see jobber detects that you haven't given a description about what you have done and so asks you for a message to enter.
I replied with Did some nice work
.
The message could be multiline but for now we use a single line.
After I entered the message jobber reports that it modified the open job and writes it down as it is now stored in the database file.
So we successfully finished our first job.
Now let's add another job we did this morning and forgot to enter then.
And this time we give all the data in the command line by using -s
and -e
with a time and the message option -m
to give the message without being asked for:
```txt
▶ jobber -s 8:15 -e 10:45 -m "What I did this morning"
Loaded database (1 entries) from file 'jobber.json'
Added new job:
Start: Sat Mar 04 2023, 08:15 End: Sat Mar 04 2023, 10:45 Hours: 2.5 Message: What I did this morning
Saved database into file 'jobber.json' ```
As you can see this also worked like a charm.
You can replace the -s
by -b
to continue a job.
Then a new job will be created like with -s
but message and tags of the last job will be taken automatically for the new one.
Instead of giving an end date and/or time with -e
you can also user -d
to give a duration of the job (see section
Durations).
If you want to categorize your jobs (e.g. to differ meetings from programming jobs) or if you have multiple clients you work for you can use tags to set this up.
Just add option -t
to give a list of tags when you create a job:
```txt ▶ jobber -s -t meeting -m "meeting about new design" -d 2:00 Loaded database (2 entries) from file 'jobber.json' There 1 warning(s) you have to omit:
WARNING 1) You have used some tags ( meeting ) which are unknown so far. Continue if you want to create them. Do you still want to add this job? (y/N) y Added new job:
Start: Sun Mar 05 2023, 21:24
End: Sun Mar 05 2023, 23:24
Hours: 2
Tags: meeting
Message: meeting about new design
Saved database into file 'jobber.json' ```
Here jobber asks you if you want to add the unknown tag meeting
and I answered yes by entering y
.
If you use -l
to display jobs you can see the tag:
```txt
▶ jobber -l
Loaded database (3 entries) from file 'jobber.json'
Pos: 1
Start: Sat Mar 04 2023, 16:25
End: Sat Mar 04 2023, 16:34
Hours: 0.25
Message: Did some nice work
Pos: 2
Start: Sat Mar 04 2023, 08:15 End: Sat Mar 04 2023, 10:45 Hours: 2.5 Message: What I did this morning
Pos: 3
Start: Sun Mar 05 2023, 21:24
End: Sun Mar 05 2023, 23:24
Hours: 2
Tags: meeting
Message: meeting about new design
Total: 3 job(s), 4.75 hours
Database unchanged. ```
Tags are colored differently after they were added so that you can easily differentiate between them (you can not see this here in this markdown file).
You can add multiple tags by listing then separated by comma (e.g. meeting,design
).
You also can use tags to differ between clients and give every client a different configuration (see section Configuration).
Let's take a look what we already did today:
```txt
▶ jobber -l
Loaded database (2 entries) from file 'jobber.json'
Pos: 1
Start: Sat Mar 04 2023, 16:25
End: Sat Mar 04 2023, 16:34
Hours: 0.25
Message: Did some nice work
Pos: 2
Start: Sat Mar 04 2023, 08:15 End: Sat Mar 04 2023, 10:45 Hours: 2.5 Message: What I did this morning
Total: 2 job(s), 2.75 hours
Database unchanged.
```
You can see that jobber lists the two jobs we did.
Let's display this in a more fancy view with the report option -r
:
```txt
▶ jobber -r
Loaded database (2 entries) from file 'jobber.json'
3/2023
day sun mon tue wed thu fri sat week
- - - 2.75 2.75
5 - - - - - - - 0
12 - - - - - - - 0
19 - - - - - - - 0
26 - - - - - 0
Mar 2023: 2.75 hrs.
Total: 2 job(s), 2.75 hours Database unchanged. ```
Wow! What you get now is a monthly report of the jobs.
Let me explain how this is to read: In the first line of the report you see the month and the year 3/2023
.
After that a table follows in which the first column shows the day of month for each line (except the first which would always be 1
).
The next seven columns show the work time for each day.
Because I write this README at Saturday under sat
you see that I worked 2.75
hours today.
In the last column the weekly work time is summed up and at the end of the table it says that we work the same amount in all of March and - as useless as it seems in our case - at the end it sums up all work time for all displayed jobs.
You might use -t
to set up some tags which will filter out every job not using these tags in all reports.
With -f
you can set which database file shall be used by jobber (will override the location read from the configuration as described in section Installation):
txt
▶ jobber -f ~/my_jobber.json` [...]
Date and time in one of the following formats:
| Format | Type | Description | Example |
| :-------------------------- | ----------- | ------------------------------- | ---------------- |
| m/
d/
y,
H:
M | month first | date and time | 1/31/2023,1:01
|
| m/
d/
y | month first | date | 1/31/2023
|
| m/
d,
H:
M | month first | date without year and with time | 1/31,1:01
|
| m/
d | month first | date without year | 1/31
|
| d.
m.
y,
H:
M | day first | date and time | 31.1.2023,1:01
|
| d.
m.
y | day first | date | 31.1.2023
|
| d.
m.,
H:
M | day first | date without year and with time | 31.1.,1:01
|
| d.
m. | day first | date without year | 31.1.
|
| y-
m-
d,
H:
M | year first | date and time | 2023-1-31,1:01
|
| y-
m-
d | year first | date | 2023-1-31
|
| H:
M | - | time | 1:01
|
Notes:
Duration in one of the following formats:
| Format | Type | Description | Example |
| :--------- | ------------------ | ----------------------------- | ------- |
| H:
M | standard | hours and minutes | 1:15
|
| h,
fr | with comma | hours and fraction of an hour | 1,25
|
| h.
fr | with decimal point | hours and fraction of an hour | 1.25
|
Time or positional range in one of the following formats:
| Format | Description | Example |
| :--------- | ------------------------- | ------------------ |
| f-
t | from position to position | 3-5
|
| f-
| since position | 3-
|
| C | count (from end) | 10
|
| s..
u | since time until time | 1/31,15:00..1.2.
|
| s..
| since time | 1/31,15:00..
|
| D | single day | 1/31
|
Hints:
31.1...1.2.
)To import the old database format of the legacy Ruby version of jobber you can use --legacy-import
:
txt
▶ jobber --legacy-import ~/my_old_jobber.dat
Loaded database (2 entries) from file 'jobber.json'
Imported 125 jobs added new tags consult , meeting , my_client , training .
Saved database into file 'jobber.json'
jobber shows that it have successfully imported 125 jobs
and that four new tags came with this import (again: tag names would be colored but not here in the Markdown text).
By using the option -E
you can export the database or parts of it into a CSV file:
txt
▶ jobber -E
Loaded database (2 entries) from file 'jobber.json'
"tags","start","hours","message"
"my_tag","03/04/2023 08:15",2.5,"What I did this morning"
"my_tag","03/04/2023 16:25",0.25,"Did some nice work"
Database unchanged.
As you can see the default output is a CSV file including the following columns: tags
, start
, hours
and message
.
Hint:
jobber -E > out.csv
)Top change the columns that are exported you can use option --csv
(possible values are: pos
, tags
, start
, end
, hours
and message
):
txt
▶ jobber -E --csv pos,start,end
Loaded database (2 entries) from file 'jobber.json'
"pos","start","hours"
2,"03/04/2023 08:15",2.5
1,"03/04/2023 16:25",0.25
Database unchanged.
In this example we just export pos
,start
and hours
only.
You may also specify a range with option -E
like when you do a report:
txt
▶ jobber -E 3/4,0:00..12:00
Loaded database (2 entries) from file 'jobber.json'
"tags","start","hours","message"
"","03/04/2023 08:15",2.5,"What I did this morning"
Database unchanged.
As you can see now only one of both jobs has been exported.
jobber does several plausibility checks of your commands. Whenever something seems unintended you will get a warning and will be asked if you still want to continue.
You are about to add a job that intersects another one in time.
```txt ▶ jobber -s 3/4,9:00 -e 10:00 Loaded database (2 entries) from file 'jobber.json' There 1 warning(s) you have to omit:
WARNING 1) The job you want to add overlaps existing one(s):
Job you want to add:
Start: Sat Mar 04 2023, 09:00 End: Sat Mar 04 2023, 10:00 Hours: 1
Existing overlapping jobs:
Pos: 2
Start: Sat Mar 04 2023, 08:15 End: Sat Mar 04 2023, 10:45 Hours: 2.5 Message: What I did this morning
Total: 1 job(s), 2.5 hours
Do you still want to add this job? (y/N) ```
jobber lists you the job you are about to add and the ones that intersect.
Hint:
Check your input and if this was intentional answer y
to continue.
With option -t
you have given some tag names which are currently unknown and *jobber then asks you if this was a mistake or you want to add a new tag:
```txt ▶ jobber -s -t consulting Loaded database (2 entries) from file 'jobber.json' There 1 warning(s) you have to omit:
WARNING 1) You have used some tags ( consulting ) which are unknown so far. Continue if you want to create them. Do you still want to add this job? (y/N) ```
In this case the tag consulting
is unknown.
To list which tags are already known you can use the option -T
(see section Tagging).
Reading or writing to file has failed.
Parsing JSON went wrong.
You have tried to start a new job but there currently is an open job which needs to be ended before you can add new jobs.
You tried to end an open job but there is none.
End and start time seems swapped in order.
You refused something after questioned.
You used two tags together which have different configurations.
You need to enter a message but you did not.
You stated a column name that is unknown when exporting into CSV (only pos
, start
, end
, hours
, message
and tags
are available).
Parsing of a date and or time went wrong.
At the first start jobber creates a configuration file (usually at ~/.config/jobber/config.toml
)
This file has currently only one entry which is:
txt
database = '~/jobber.json'
Change the path of the database if you like.
There are some settings in jobber you may want to change:
In jobber there is a base configuration but you also can attach configurations to tags to have different configurations for different clients.
With -R
you can set the work time resolution.
The default is 0.25
which means a quarter of an hour.
So if you add for example a job with a duration of 16 minutes this will be rounded up to 30 minutes.
For example you might change the base resolution to half an hour with:
```txt
▶ jobber -R 0.5
Beginning new database file 'jobber.json'
Changed the following default configuration values:
Resolution: 0.5 hours
Saved database into file 'jobber.json' ```
To change your hourly payment rate use -P
(e.g. jobber -P 50
to set your hourly rate to 50$).
There is not default so if you do not set this rates will not be displayed.
If you do jobber lists costs in the list view.
```txt ▶ jobber -P 100 Loaded database (0 entries) from file 'jobber.json' Changed the following default configuration values:
Payment per hour: 100
Saved database into file 'jobber.json' ```
If you set this value with -H
days which work time exceeds this value will be marked yellow in report view.
In List view jobs that exceed this value will be marked yellow.
So if you want to change the maximum hours for a day to 8 use:
```txt
▶ jobber -H 8
Loaded database (0 entries) from file 'jobber.json'
Changed the following default configuration values:
Maximum work time: 8 hours
Saved database into file 'jobber.json' ```
If you have several clients and each one has for example different payment rates you can add the tag option -t
when you set the configuration.
To show your configuration(s) use the option -C
:
```txt
▶ jobber -C
Loaded database (3 entries) from file 'jobber.json'
Base Configuration:
Resolution: 0.5 hours Payment per hour: 100 Maximum work time: 8 hours
Database unchanged. ```