Final commit before re-publication

This commit is contained in:
2025-08-23 09:34:15 -04:00
parent 58830d9be8
commit d0fcd32c91
6 changed files with 401 additions and 40 deletions

View File

@@ -1,5 +1,5 @@
# timetracker
tblancher's CLI-based time tracking system (see demo videos of the [timetracker setup](https://pindrop.zoom.us/rec/share/wvN6FoPfyEhJfo3x12qFVKofHL30X6a81Sce__IJmEp90tBtwdKHn7JnxZMQfz69), [macro setup](https://pindrop.zoom.us/rec/share/w-lYBpf2q0hLYpHR-n7bY6gwMr_Caaa81ClK__YJmR2E6NY1ybj-wurKfyog0FpO), and [Clarizen process](https://pindrop.zoom.us/rec/share/yuF4C7_7rFlJAYnAq2TwarETAorMeaa8gXQdqfUPnRsgkXJf9_ByKUpI8hnGW1Jp))
tblancher's CLI-based time tracking system
## INSTALLATION
See [INSTALL_Linux.md](INSTALL_Linux.md) or [INSTALL_macOS.md](INSTALL_macOS.md) in this repository.
@@ -48,18 +48,19 @@ think they're different tasks).
Certain strings have special meaning to timetracker. The category name in
square brackets specifies that the task is related to a specific customer, or
should be tracked on a certain item in Clarizen, to make transferring to
Clarizen more straightforward. These can be any string, even with spaces, but
beware of using shell special characters, or special regular expression
characters. The names can be anything, so things like `[Project Phoenix]`, `[Java training]`,
`[Commute]`, or `[Internal]` are perfectly valid. For the author's most
common categories, macros are set up with text string triggers in Keyboard
Maestro (more on that below). If you decide to use `timetracker.py` (the
Python 3 script), the category (in square-brackets) is optional, but won't have
a separate section in `do_process.sh` (though it will reflect in the grand
total at the end). If you decide to use the Rust programs, the category is
**required**, or else the Rust programs will panic and error out. It is highly
recommended to use the Rust programs, for speed if nothing else.
should be tracked on a certain item in the official timelog, to make
transferring to the official timesheet more straightforward. These can be any string, even
with spaces, but beware of using shell special characters, or special regular
expression characters. The names can be anything, so things like `[Project
Phoenix]`, `[Java training]`, `[Commute]`, or `[Internal]` are perfectly valid.
For the author's most common categories, macros are set up with text string
triggers in Keyboard Maestro (more on that below). If you decide to use
`timetracker.py` (the Python 3 script), the category (in square-brackets) is
optional, but won't have a separate section in `do_process.sh` (though it will
reflect in the grand total at the end). If you decide to use the Rust
programs, the category is **required**, or else the Rust programs will panic
and error out. It is highly recommended to use the Rust programs, for speed if
nothing else.
Note that the aggregate programs (`do_process.sh`, `doprocess` [Rust],
`chug.sh`, `chug` [Rust]) expect the log file to be named by the ISO-8601 date
@@ -86,7 +87,7 @@ amount of time I was spending during my day.
## timetracker in Rust
Again, see the [INSTALL.md](https://github.atl.pdrop.net/tblancher/timetracker/blob/master/INSTALL.md) guide in this repository for instructions on building the Rust programs. It is highly recommended to use the Rust programs instead of the older Python and Bash scripts below, if only because the Rust programs are much, much faster to execute than the older scripts. The usage is straightforward:
Again, see the [INSTALL_Linux.md](https:/git.eldon.me/trey/timetracker/primary/INSTALL_Linux.md) or [INSTALL_macOS.md](https:/git.eldon.me/trey/timetracker/primary/INSTALL_macOS.md) guides in this repository for instructions on building the Rust programs. It is highly recommended to use the Rust programs instead of the older Python and Bash scripts below, if only because the Rust programs are much, much faster to execute than the older scripts. The usage is straightforward:
### timetracker usage
Pass the log name as the only argument to `timetracker`. Alternatively, you can execute a command pipeline that generates valid log output in the format above, piping it into timetracker:
@@ -112,7 +113,7 @@ Grand total: 7.16
This is the only Rust program that does not necessarily assume the log will be named in the ISO-8601 date format with `.log` filename extension (e.g. `2022-11-30.log`, `2022-12-19.log`, etc.). You can run this periodically throughout the day as you build the log file to see how much time you've put in thus far.
### doprocess usage
`doprocess` relies on the same internal Rust functions as `timetracker`, with the added output feature of separating the various categories into their own sections, for even easier transfer to Clarizen. With the new Clarizen categories, this makes entry into Clarizen take five minutes or less. You may want to sort your categories in Clarizen, to match the sort out of `doprocess`. Each section has its own total, with a running subtotal you can use to confirm you haven't missed anything as you transfer them to Clarizen. Its output looks like this:
`doprocess` relies on the same internal Rust functions as `timetracker`, with the added output feature of separating the various categories into their own sections, for even easier transfer to the official timesheet. Each category will hav its own subtotal, with a running subtotal you can use to confirm you haven't missed anything as you transfer the entries to the official timesheet. Its output looks like this:
```
[Cloud] Customer 1 PDROP-0000000 case-related task 1 0.75hrs
[Cloud] Customer 1 task 1 0.08hrs
@@ -141,10 +142,10 @@ Subtotal: 7.16hrs
Grand total: 7.16
```
For everything but the [Internal] category, you should be able to copy the entire section with Section total to a single line item in Clarizen. The Section total and Subtotal for the [Internal] category can be input as separate line items for each entry, and these totals help ensure you haven't missed one or input its duration improperly.
For everything but the [Internal] category, you should be able to copy the entire section with Section total to a single line item in the official timesheet. The Section total and Subtotal for the [Internal] category can be input as separate line items for each entry, and these totals help ensure you haven't missed one or input its duration improperly.
### chug usage
`chug` does not take a filename, or a log in the above format. Instead, it looks at the current week, and calculates the grand total for each day. If any day is missing, because the log file doesn't exist, it will print 0.00 for that day, like so:
`chug` does not take a filename, or a log in the above format. Instead, it looks at the current week starting on Monday, and calculates the grand total for each day by examining each log file (this is why it's stongly recommended to have one log per day, with the date in the filename). If any day is missing, because the log file doesn't exist, it will print 0.00 for that day, like so:
```
2022-12-19.log
@@ -170,7 +171,7 @@ For everything but the [Internal] category, you should be able to copy the entir
Grand total: 8.38
```
You can use this to review Clarizen, and make sure all time is input correctly. If you'd like to look at a previous week, you can pass the optional argument `1` or `+1`, `n` or `+n` where `n` is an unsigned integer for even further back. If you will be out of office on extended leave for the next week, and wish to run `chug` for it, pass a negative integer (e.g. `-1`, or `-n`). The formula for the week `chug` will look at is as follows:
You can use this to review the official timesheet, and make sure all time is input correctly. If you'd like to look at a previous week, you can pass the optional argument `1` or `+1`, `n` or `+n` where `n` is an unsigned integer for even further back. If you will be out of office on extended leave for the next week, and wish to run `chug` for it, pass a negative integer (e.g. `-1`, or `-n`). The formula for the week `chug` will look at is as follows:
```
<last Monday> - <week offset>
@@ -189,12 +190,24 @@ Similarly, if you have too many End timestamps, you'll get an error that looks l
thread 'main' panicked at 'ERROR: Missing a Begin', timelogging/src/lib.rs:101:21
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
```
For correct operation, there should be an equal number of Begin and End timestamps. If you're in the middle of a task, the last End is optional, if it's the first entry of that task it will be the minimum duration (0.08 hours).
For correct operation, there should be an equal number of Begin and End timestamps. If you're in the middle of a task, the last End is optional; if it's the first entry of that task it will be the minimum duration (0.08 hours).
# Older Python and Bash scripts, for comparison
## timetracker.py usage
The timetracker.py script is the basis, it tallies the time for each task and then outputs a report on how much each task takes to complete. It takes as its argument one or more text files, the log files in the format above. It should only report one line item per task, regardless of how many times it appears in the log. Each task should have a category/tag in square brackets, the behavior of `do_process.sh` (see below) is now undefined if the tag is left out.
Note that the time gets rounded to the nearest quarter hour. If it would round to zero hours (0.00hrs), the script replaces it 0.08hrs, which corresponds to 288 seconds. If you don't want a task to be set to 0.08hrs, simply leave it out of the log. Prior to the merge of nearest-quarter-hour, everything was rounded UP to the nearest quarter hour. That meant that if a task took 30 minutes and one second, it would be rounded UP to 0.75hrs (45 minutes). On longer days this had the effect of inflating the daily total, such that 10 hours of actual work was being inflated to 12 or even 13 hours on some occasions. Now that it rounds up or down to the nearest quarter hour, timetracker.py is much more accurate. There still is a bit of inflation for the short tasks (anything taking less than 288 seconds), but it shouldn't be as bad as adding an extra 15 minutes to tasks that are close to quarter hour boundaries.
Note that the time gets rounded to the nearest quarter hour. If it would round
to zero hours (0.00hrs), the script replaces it with 0.08hrs, which corresponds
to 288 seconds. If you don't want a task to be set to 0.08hrs, simply leave it
out of the log. Prior to the merge of nearest-quarter-hour, everything was
rounded UP to the nearest quarter hour. That meant that if a task took 30
minutes and one second, it would be rounded UP to 0.75hrs (45 minutes). On
longer days this had the effect of inflating the daily total, such that 10
hours of actual work was being inflated to 12 or even 13 hours on some
occasions. Now that it rounds up or down to the nearest quarter hour,
timetracker.py is much more accurate. There still is a bit of inflation for
the short tasks (anything taking less than 288 seconds), but it shouldn't be as
bad as adding an extra 15 minutes to tasks that are close to quarter hour
boundaries.
The output looks like this:
@@ -216,7 +229,7 @@ Section total: 8.41hrs
You may have noticed, the output of timetracker.py is in alphabetical order by category, then by task. This follows for `./do_process.sh` and `./chug.sh` below.
## `do_process.sh`
This script filters the output of timetracker.py, giving each category (in square brackets) its own section, with its own tallies. The header is the list of categories and the log file basename (below this is `example.log`, but would normally be a date such as `2017-12-08.log`). After the header, each line of output and sections are designed to be directly transferred to Clarizen manually, and the tally used to verify the daily and weekly totals in Clarizen. It calculates the time total for each organization/category. It also prints the subtotal thus far, to be sure no items are missed when adding them to Clarizen. At the end it prints a grand total for the day, which should be used along with the subtotals to cross-verify in Clarizen.
This script filters the output of timetracker.py, giving each category (in square brackets) its own section, with its own subtallies. The header is the list of categories and the log file basename (below this is `example.log`, but would normally be a date such as `2017-12-08.log`). After the header, each line of output and sections are designed to be directly transferred to the official timesheet manually, and the tally used to verify the daily and weekly totals in the official timesheet. It calculates the time total for each organization/category. It also prints the subtotal thus far, to be sure no items are missed when adding them to the official timesheet. At the end it prints a grand total for the day, which should be used along with the subtotals to cross-verify in the official timesheet.
```
[Internal]
@@ -265,14 +278,14 @@ Grand total: 8.41hrs
It takes as its argument a filename with the current date log (`date +%F` format, such as `./do_process.sh 2020-03-12.log`), or it assumes the current date log file. Also, arbitrary filenames can be passed, so `example.log` becomes `./do_process.sh example.log`.
Projects in Clarizen are listed alphabetically, so to transfer data from the `./do_process.sh` output you simply copy the data lines from the ouput, and paste it into the notes section of the Clarizen entry. Enter the duration of the task at the top of the Clarizen entry, and select the category and subcategory of the entry.
Projects in the official timesheet are listed alphabetically, so to transfer data from the `./do_process.sh` output you simply copy the data lines from the ouput, and paste it into the notes section of the official timesheet entry. Enter the duration of the task at the top of the official timesheet entry, and select the category and subcategory of the entry.
## `chug.sh`
This script is designed to be run on Mondays, after the previous week of log files have been generated and closed out. The standard Monday usage takes no arguments, it expects all log files to be processed to be in the current directory. It runs `do_process.sh` once for each day of the previous week, cleanly skipping any log files which do not exist. It pauses after each day report is output, allowing the user to transfer the times manually to Clarizen.
This script is designed to be run on Mondays, after the previous week of log files have been generated and closed out. The standard Monday usage takes no arguments, it expects all log files to be processed to be in the current directory. It runs `do_process.sh` once for each day of the previous week, cleanly skipping any log files which do not exist. It pauses after each day report is output, allowing the user to transfer the times manually to the official timesheet.
`./chug.sh` takes a single optional argument, a week offset (in case `./chug.sh` is executed for log files further back than last week). This uses the GNU date functionality of calculating "last Monday." On Monday this will be "today - 7 days", but on the following Tuesday this will evaluate to "yesterday". If Monday is a holiday and you're entering your timesheets on Tuesday you can enter `./chug.sh 1` and it should do the right thing. If it's the first Monday of the month and you need to process the previous four weeks of logs, use `./chug.sh 4`. The output of `./do_process.sh` prints the date that is being processed at the top, if your incantation of `./chug.sh` is wrong, you can quit and adjust accordingly. `./chug.sh` with no arguments is equivalent to `./chug.sh 0`.
The output is the output of `./do_process.sh` piped to `less` for each day, pausing so the user can go through that day's output and transfer the items to Clarizen. If no time was logged for a given day (the file does not exist), `./chug.sh` prints the missing date, but otherwise silently skips it. All seven days of the week are processed, Monday through Sunday.
The output is the output of `./do_process.sh` piped to `less` for each day, pausing so the user can go through that day's output and transfer the items to the official timesheet. If no time was logged for a given day (the file does not exist), `./chug.sh` prints the missing date, but otherwise silently skips it. All seven days of the week are processed, Monday through Sunday.
If you're only interested in the weekly summary (and don't want the output of `./do_process.sh <date>.log | less`), you can pass the `-i` option to `./chug.sh`, like so: `./chug -i`, or if you need a prior week, e.g. `./chug -i 2`. The output will look similar to the following:
@@ -302,16 +315,16 @@ Weekly Total: 48.79
```
## month-pack.sh
timetracker.py and the related `do_process.sh` and `chug.sh` scripts are designed to have each day with its own YYYY-MM-DD.log file in the current, timetracker directory. Over time, the log files in this directory can become quite numerous and unwieldy. To help combat this, `month-pack.sh` takes all the log files from the previous month, adds them to a compressed tarball, and deletes them from the directory. It is designed to be run once all of the log files for the previous month have been processed into Clarizen.
timetracker.py and the related `do_process.sh` and `chug.sh` scripts are designed to have each day with its own YYYY-MM-DD.log file in the current, timetracker directory. Over time, the log files in this directory can become quite numerous and unwieldy. To help combat this, `month-pack.sh` takes all the log files from the previous month, adds them to a compressed tarball, and deletes them from the directory. It is designed to be run once all of the log files for the previous month have been processed into the official timesheet.
## year-pack.sh
In the same vein as month-pack.sh, year-pack.sh tars up all the monthly tarballs (named YYYY-MM.tar.xz), and puts them into a single YYYY.tar file. It is designed to be run in January when all of the previous December log files have been processed. All of the YYYY-MM.tar.xz files will be deleted once the YYYY.tar file is created.
# CAVEATS
## Tallies
Since I (the author, Trey Blancher) have been using this system to keep track of time, I've noticed that sometimes either Clarizen or these scripts get slightly off. Usually it's no more than 0.25 hours off in the tallies, but it gets time consuming trying to track down where the tally went wrong. If I do find the culprit, it's usually because I've entered the wrong time for a specific task in Clarizen (i.e., entering '0.08' instead of '0.25' for some tasks), or I've entered the time in the wrong cell.
Since I (the author, Trey Blancher) have been using this system to keep track of time, I've noticed that sometimes either the official timesheet or these scripts get slightly off. Usually it's no more than 0.25 hours off in the tallies, but it gets time consuming trying to track down where the tally went wrong. If I do find the culprit, it's usually because I've entered the wrong time for a specific task in the official timesheet (i.e., entering '0.08' instead of '0.25' for some tasks), or I've entered the time in the wrong cell.
### 2020-09-16 UPDATE
As of the institution of the running subtotals, the tallies being off in Clarizen is a *MUCH* less frequent problem. Usually if Clarizen is off it's because I missed an entry, or Clarizen didn't absorb an entry properly (that happens from time to time).
As of the institution of the running subtotals, the tallies being off in the official timesheet is a *MUCH* less frequent problem. Usually if the official timesheet is off it's because I missed an entry, or the official timesheet didn't absorb an entry properly (that happens from time to time).
## vim
The vim-specific files in this repository are tailored for my tastes. One big item of note, I've disabled vim cursor navigation with the arrow keys (Up, Down, Left, Right), to force me to get into the habit of using h, j, k, l for cursor navigation, and only navigate in normal mode (not insert mode). You will probably want to delete the following lines from .vimrc if you're not interested in the true Vim way®:
@@ -345,6 +358,6 @@ The 'End' macro copies the category and task name from the previous 'Begin' macr
2020-03-11 19:30:36: End [Internal] timetracker doc
2020-03-11 19:30:36: Begin
```
I also have Keyboard Maestro text string triggers for common categories, to minimize typing. For instance, the text string triggers `[css` becomes `[Internal] `, `[pro` becomes `[Internal] `, `[mm` or `[MM` becomes `[Mass Mutual] `, `[vzw` becomes `[Verizon Wireless] `, `[pin` becomes `[Company] ` (to match the Pindrop related items in Clarizen), etc. These are included in `timetracker.kmmacros` for your convenience.
I also have Keyboard Maestro text string triggers for common categories, to minimize typing. For instance, the text string triggers `[css` becomes `[Internal] `, `[pro` becomes `[Internal] `, `[mm` or `[MM` becomes `[Mortimer Mouse] `, `[vzw` becomes `[Vizier Works] `, `[pin` becomes `[Company] ` (to match the Pindrop related items in the official timesheet), etc. These are included in `timetracker.kmmacros` for your convenience.
See [INSTALL.md](https://github.atl.pdrop.net/tblancher/timetracker/blob/master/INSTALL.md) in this repository for a detailed explanation of how to use the `timetracker.kmmacros` and set up the vim macros.
See [INSTALL_macOS.md](https://git.eldon.me/trey/timetracker/blob/primary/INSTALL_macOS.md) in this repository for a detailed explanation of how to use the `timetracker.kmmacros` and set up the vim macros.