16 KiB
- Chronometrist
- Getting started
- How-to guides
- Explanation
- Reference
- Legend of currently-used time formats
- chronometrist-common.el
- chronometrist-custom.el
- chronometrist-diary-view.el
- chronometrist.el
- chronometrist-events.el
- chronometrist-migrate.el
- chronometrist-plist-pp.el
- chronometrist-queries.el
- chronometrist-report-custom.el
- chronometrist-report.el
- chronometrist-key-values.el
- chronometrist-statistics-custom.el
- chronometrist-statistics.el
- chronometrist-time.el
- chronometrist-timer.el
- chronometrist-goals
- chronometrist-sexp
Chronometrist
Getting started
Installation
Usage
How-to guides
Explanation
Design goals
-
Don't make assumptions about the user's profession
- e.g. timeclock seems to assume you're using it for a 9-to-5/contractor job
-
Incentivize use
- Hooks allow the time tracker to automate tasks and become a useful part of your workflow
-
Make it easy to edit data using existing, familiar tools
- We don't use an SQL database, where changing a single field is tricky [1]
- We use a text file containing s-expressions (easy for humans to read and write)
- We use ISO-8601 for timestamps (easy for humans to read and write) rather than UNIX epoch time
- Reduce human errors in tracking
- Have a useful, informative, interactive interface
- Support mouse and keyboard use equally
[1] I still have doubts about this. Having SQL as a query language would be very useful in perusing the stored data. Maybe we should have tried to create a companion mode to edit SQL databases interactively?
Midnight-spanning events
A unique problem in working with Chronometrist, one I had never foreseen, was tasks which start on one day and end on another. These mess up data consumption (especially interval calculations and acquiring data for a specific date) in all sorts of unforeseen ways.
There are a few different approaches of dealing with them. (Currently, Chronometrist uses #3.)
1. (timeclock format) When the code of the first event in the day is "o", it's a midnight-spanning event.
- Advantage - very simple to detect
- Disadvantage - "in" and "out" events must be represented separately
2. Split them at the file level
- Advantage - operation is performed only once for each such event + simpler data-consuming code + reduced post-parsing load.
-
What happens when the user changes their day-start-time? The split-up events are now split wrongly, and the second event may get split again. Possible solutions -
- Add function to check if, for two events A and B, the :stop of A is the same as the :start of B, and that all their other tags are identical. Then we can re-split them according to the new day-start-time.
- Add a :split tag to split events. It can denote that the next event was originally a part of this one.
-
Re-check and update the file when the day-start-time changes.
- Possible with
add-variable-watcher
or:custom-set
in Customize (thanks bpalmer)
- Possible with
3. Split them at the hash-table-level
Handled by chronometrist-sexp-events-populate
- Advantage - simpler data-consuming code.
4. Split them at the data-consumer level (e.g. when calculating time for one day/getting events for one day)
- Advantage - reduced repetitive post-parsing load.
Reference
Legend of currently-used time formats
1. ts
ts.el struct
- Used by nearly all internal functions
2. iso-timestamp
"YYYY-MM-DDTHH:MM:SSZ"
- Used in the s-expression file format
- Read by chronometrist-sexp-events-populate
- Used in the plists in the chronometrist-events hash table values
3. iso-date
"YYYY-MM-DD"
- Used as hash table keys in chronometrist-events - can't use ts structs for keys, you'd have to make a hash table predicate which uses ts=
4. seconds
integer seconds as duration
- Used for most durations
- May be changed to floating point to allow larger durations. The minimum range of `most-positive-fixnum` is 536870911, which seems to be enough to represent durations of 17 years.
- Used for update intervals (chronometrist-update-interval, chronometrist-change-update-interval)
5. minutes
integer minutes as duration
- Used for goals (chronometrist-goals-list, chronometrist-get-goal) - minutes seems like the ideal unit for users to enter
6. list-duration
(hours minute seconds)
- Only returned by chronometrist-seconds-to-hms, called by chronometrist-format-time
chronometrist-common.el
- Variable - chronometrist-empty-time-string
- Variable - chronometrist-date-re
- Variable - chronometrist-time-re-ui
- Variable - chronometrist-task-list
- Internal Variable - chronometrist–fs-watch
- Function - chronometrist-current-task ()
-
Function - chronometrist-format-time (seconds &optional (blank " "))
- seconds -> "hⓂ️s"
- Function - chronometrist-common-file-empty-p (file)
- Function - chronometrist-common-clear-buffer (buffer)
- Function - chronometrist-format-keybinds (command map &optional firstonly)
-
Function - chronometrist-events->ts-pairs (events)
- (plist …) -> ((ts . ts) …)
-
Function - chronometrist-ts-pairs->durations (ts-pairs)
- ((ts . ts) …) -> seconds
-
Function - chronometrist-previous-week-start (ts)
- ts -> ts
chronometrist-custom.el
- Custom variable - chronometrist-file
- Custom variable - chronometrist-buffer-name
- Custom variable - chronometrist-hide-cursor
- Custom variable - chronometrist-update-interval
- Custom variable - chronometrist-activity-indicator
- Custom variable - chronometrist-day-start-time
chronometrist-diary-view.el
- Variable - chronometrist-diary-buffer-name
- Internal Variable - chronometrist-diary–current-date
- Function - chronometrist-intervals-on (date)
- Function - chronometrist-diary-tasks-reasons-on (date)
- Function - chronometrist-diary-refresh (&optional ignore-auto noconfirm date)
- Major Mode - chronometrist-diary-view-mode
- Command - chronometrist-diary-view (&optional date)
chronometrist.el
- Internal Variable - chronometrist–task-history
- Internal Variable - chronometrist–point
- Keymap - chronometrist-mode-map
- Command - chronometrist-open-log (&optional button)
- Function - chronometrist-common-create-file ()
-
Function - chronometrist-task-active? (task)
- String -> Boolean
- Function - chronometrist-use-goals? ()
- Function - chronometrist-activity-indicator ()
- Function - chronometrist-entries ()
- Function - chronometrist-task-at-point ()
- Function - chronometrist-goto-last-task ()
- Function - chronometrist-print-keybind (command &optional description firstonly)
- Function - chronometrist-print-non-tabular ()
- Function - chronometrist-goto-nth-task (n)
- Function - chronometrist-refresh (&optional ignore-auto noconfirm)
- Function - chronometrist-refresh-file (fs-event)
- Command - chronometrist-query-stop ()
- Command - chronometrist-in (task &optional _prefix)
- Command - chronometrist-out (&optional _prefix)
- Variable - chronometrist-before-in-functions
- Variable - chronometrist-after-in-functions
- Variable - chronometrist-before-out-functions
- Variable - chronometrist-after-out-functions
- Function - chronometrist-run-functions-and-clock-in (task)
- Function - chronometrist-run-functions-and-clock-out (task)
- Keymap - chronometrist-mode-map
- Major Mode - chronometrist-mode
- Function - chronometrist-toggle-task-button (button)
- Function - chronometrist-add-new-task-button (button)
- Command - chronometrist-toggle-task (&optional prefix inhibit-hooks)
- Command - chronometrist-toggle-task-no-hooks (&optional prefix)
- Command - chronometrist-add-new-task ()
- Command - chronometrist (&optional arg)
chronometrist-events.el
-
Variable - chronometrist-events
- keys - iso-date
-
Function - chronometrist-day-start (timestamp)
- iso-timestamp -> encode-time
-
Function - chronometrist-file-clean ()
- commented out, unused
- Function - chronometrist-events-maybe-split (event)
- Function - chronometrist-events-populate ()
- Function - chronometrist-tasks-from-table ()
-
Function - chronometrist-events-subset (start end)
- ts ts -> hash-table
- Function - chronometrist-events-query-spec-match-p (plist specifiers)
- Function - chronometrist-events-query (table &key get specifiers except)
chronometrist-migrate.el
- Variable - chronometrist-migrate-table
- Function - chronometrist-migrate-populate (in-file)
- Function - chronometrist-migrate-timelog-file->sexp-file (&optional in-file out-file)
- Function - chronometrist-migrate-check ()
chronometrist-plist-pp.el
- Variable - chronometrist-plist-pp-keyword-re
- Variable - chronometrist-plist-pp-whitespace-re
- Function - chronometrist-plist-pp-longest-keyword-length ()
- Function - chronometrist-plist-pp-buffer-keyword-helper ()
- Function - chronometrist-plist-pp-buffer ()
- Function - chronometrist-plist-pp-to-string (object)
- Function - chronometrist-plist-pp (object &optional stream)
chronometrist-queries.el
-
Function - chronometrist-last ()
- -> plist
-
Function - chronometrist-task-time-one-day (task &optional (ts (ts-now)))
- String &optional ts -> seconds
-
Function - chronometrist-active-time-one-day (&optional ts)
- &optional ts -> seconds
- Function - chronometrist-statistics-count-active-days (task &optional (table chronometrist-events))
- Function - chronometrist-task-events-in-day (task ts)
chronometrist-report-custom.el
- Custom variable - chronometrist-report-buffer-name
- Custom variable - chronometrist-report-week-start-day
- Custom variable - chronometrist-report-weekday-number-alist
chronometrist-report.el
- Internal Variable - chronometrist-report–ui-date
- Internal Variable - chronometrist-report–ui-week-dates
- Internal Variable - chronometrist-report–point
- Function - chronometrist-report-date ()
-
Function - chronometrist-report-date->dates-in-week (first-date-in-week)
- ts-1 -> (ts-1 … ts-7)
- Function - chronometrist-report-date->week-dates ()
- Function - chronometrist-report-entries ()
- Function - chronometrist-report-print-keybind (command &optional description firstonly)
- Function - chronometrist-report-print-non-tabular ()
- Function - chronometrist-report-refresh (&optional _ignore-auto _noconfirm)
- Function - chronometrist-report-refresh-file (_fs-event)
- Keymap - chronometrist-report-mode-map
- Major Mode - chronometrist-report-mode
- Function - chronometrist-report (&optional keep-date)
- Function - chronometrist-report-previous-week (arg)
- Function - chronometrist-report-next-week (arg)
chronometrist-key-values.el
- Internal Variable - chronometrist–tag-suggestions
- Internal Variable - chronometrist–value-suggestions
- Function - chronometrist-plist-remove (plist &rest keys)
- Function - chronometrist-maybe-string-to-symbol (list)
- Function - chronometrist-maybe-symbol-to-string (list)
- Function - chronometrist-append-to-last (tags plist)
- Variable - chronometrist-tags-history
- Function - chronometrist-tags-history-populate ()
- Function - chronometrist-tags-history-combination-strings (task)
- Function - chronometrist-tags-history-individual-strings (task)
- Function - chronometrist-tags-prompt (task &optional initial-input)
- Function - chronometrist-tags-add (&rest args)
- Custom Variable - chronometrist-kv-buffer-name
- Variable - chronometrist-key-history
- Variable - chronometrist-value-history
- Function - chronometrist-ht-history-prep (table)
- Function - chronometrist-key-history-populate ()
- Function - chronometrist-value-history-populate ()
- Keymap - chronometrist-kv-read-mode-map
- Major Mode - chronometrist-kv-read-mode
- Function - chronometrist-kv-completion-quit-key ()
- Function - chronometrist-string-has-whitespace-p (string)
- Function - chronometrist-key-prompt (used-keys)
- Function - chronometrist-value-prompt (key)
- Function - chronometrist-value-insert (value)
- Function - chronometrist-kv-add (&rest args)
- Command - chronometrist-kv-accept ()
- Command - chronometrist-kv-reject ()
chronometrist-statistics-custom.el
- Custom variable - chronometrist-statistics-buffer-name
chronometrist-statistics.el
- Internal Variable - chronometrist-statistics–ui-state
- Internal Variable - chronometrist-statistics–point
-
Function - chronometrist-statistics-count-average-time-spent (task &optional (table chronometrist-events))
- string &optional hash-table -> seconds
- Function - chronometrist-statistics-entries-internal (table)
- Function - chronometrist-statistics-entries ()
- Function - chronometrist-statistics-print-keybind (command &optional description firstonly)
- Function - chronometrist-statistics-print-non-tabular ()
- Function - chronometrist-statistics-refresh (&optional ignore-auto noconfirm)
- Keymap - chronometrist-statistics-mode-map
- Major Mode - chronometrist-statistics-mode
- Command - chronometrist-statistics (&optional preserve-state)
- Command - chronometrist-statistics-previous-range (arg)
- Command - chronometrist-statistics-next-range (arg)
chronometrist-time.el
-
Function - chronometrist-iso-timestamp->ts (timestamp)
- iso-timestamp -> ts
-
Function - chronometrist-iso-date->ts (date)
- iso-date -> ts
-
Function - chronometrist-date (&optional (ts (ts-now)))
- &optional ts -> ts (with time 00:00:00)
- Function - chronometrist-format-time-iso8601 (&optional unix-time)
- Function - chronometrist-midnight-spanning-p (start-time stop-time)
-
Function - chronometrist-seconds-to-hms (seconds)
- seconds -> list-duration
chronometrist-timer.el
- Internal Variable - chronometrist–timer-object
- Function - chronometrist-timer ()
- Command - chronometrist-stop-timer ()
- Command - chronometrist-maybe-start-timer (&optional interactive-test)
- Command - chronometrist-force-restart-timer ()
- Command - chronometrist-change-update-interval (arg)
chronometrist-goals
- Internal Variable - chronometrist–timers-list
- Custom Variable - chronometrist-goals-list nil
- Function - chronometrist-run-at-time (time repeat function &rest args)
-
Function - chronometrist-seconds->alert-string (seconds)
- seconds -> string
-
Function - chronometrist-approach-alert (task goal spent)
- string minutes minutes
-
Function - chronometrist-complete-alert (task goal spent)
- string minutes minutes
-
Function - chronometrist-exceed-alert (task goal spent)
- string minutes minutes
-
Function - chronometrist-no-goal-alert (task goal spent)
- string minutes minutes
-
Custom Variable - chronometrist-goals-alert-functions
- each function is passed - string minutes minutes
-
Function - chronometrist-get-goal (task &optional (goals-list chronometrist-goals-list))
- String &optional List -> minutes
- Function - chronometrist-goals-run-alert-timers (task)
- Function - chronometrist-goals-stop-alert-timers (&optional _task)
- Function - chronometrist-goals-on-file-change ()
chronometrist-sexp
- Function - chronometrist-sexp-open-log ()
-
Function - chronometrist-sexp-last ()
- -> plist
- Function - chronometrist-sexp-current-task ()
- Function - chronometrist-sexp-events-populate ()
- Function - chronometrist-sexp-create-file ()
- Function - chronometrist-sexp-new (plist &optional (buffer (find-file-noselect chronometrist-file)))
- Function - chronometrist-sexp-delete-list (&optional arg)
- Function - chronometrist-sexp-replace-last (plist)
- Command - chronometrist-sexp-reindent-buffer ()