dey 0.2.0__tar.gz → 0.2.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dey-0.2.2/LICENSE +18 -0
- dey-0.2.2/PKG-INFO +409 -0
- {dey-0.2.0 → dey-0.2.2}/README.md +12 -16
- {dey-0.2.0 → dey-0.2.2}/dey/cli.py +51 -4
- dey-0.2.2/dey.egg-info/PKG-INFO +409 -0
- {dey-0.2.0 → dey-0.2.2}/dey.egg-info/SOURCES.txt +1 -0
- {dey-0.2.0 → dey-0.2.2}/pyproject.toml +8 -1
- dey-0.2.0/PKG-INFO +0 -5
- dey-0.2.0/dey.egg-info/PKG-INFO +0 -5
- {dey-0.2.0 → dey-0.2.2}/dey/__init__.py +0 -0
- {dey-0.2.0 → dey-0.2.2}/dey/__main__.py +0 -0
- {dey-0.2.0 → dey-0.2.2}/dey.egg-info/dependency_links.txt +0 -0
- {dey-0.2.0 → dey-0.2.2}/dey.egg-info/entry_points.txt +0 -0
- {dey-0.2.0 → dey-0.2.2}/dey.egg-info/top_level.txt +0 -0
- {dey-0.2.0 → dey-0.2.2}/setup.cfg +0 -0
dey-0.2.2/LICENSE
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
Copyright 2026 David Woodburn
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining acopy of
|
|
4
|
+
this software and associated documentation files (the"Software"), to deal in the
|
|
5
|
+
Software without restriction, includingwithout limitation the rights to use,
|
|
6
|
+
copy, modify, merge, publish,distribute, sublicense, and/or sell copies of the
|
|
7
|
+
Software, and topermit persons to whom the Software is furnished to do so,
|
|
8
|
+
subject tothe following conditions:
|
|
9
|
+
|
|
10
|
+
The above copyright notice and this permission notice shall be includedin all
|
|
11
|
+
copies or substantial portions of the Software.
|
|
12
|
+
|
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESSOR
|
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OFMERCHANTABILITY, FITNESS
|
|
15
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR
|
|
16
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANYCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
|
17
|
+
AN ACTION OF CONTRACT,TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
18
|
+
WITH THESOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
dey-0.2.2/PKG-INFO
ADDED
|
@@ -0,0 +1,409 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: dey
|
|
3
|
+
Version: 0.2.2
|
|
4
|
+
Summary: Terminal time tracker
|
|
5
|
+
Author-email: David Woodburn <david.woodburn@icloud.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Requires-Python: >=3.7
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Dynamic: license-file
|
|
11
|
+
|
|
12
|
+
# Introduction
|
|
13
|
+
|
|
14
|
+
`dey` is a terminal-based time tracker for logging work hours against named
|
|
15
|
+
jobs.
|
|
16
|
+
|
|
17
|
+
The name comes from the [Alexander Dey Time Register Clock][1] (1888), an early
|
|
18
|
+
punch-clock that recorded employee hours on a paper roll. Like its namesake,
|
|
19
|
+
`dey` uses a simple punch-in, punch-out model: start a timer against a job, stop
|
|
20
|
+
it later. You can also backfill entries for past times.
|
|
21
|
+
|
|
22
|
+
Using a spreadsheet to track work hours is cumbersome: Excel is slow to open,
|
|
23
|
+
times and dates must be entered manually, multiple jobs create an unwieldy
|
|
24
|
+
number of columns, and generating summaries is complicated. This program offers
|
|
25
|
+
a simple terminal-based alternative. It automatically records the current date
|
|
26
|
+
and time, resolves short job-name fragments by substring matching, and produces
|
|
27
|
+
clear daily and weekly summaries that can be filtered the same way. A single
|
|
28
|
+
command also lets you undo the last entry, adjust its time, or change its job.
|
|
29
|
+
|
|
30
|
+
The design deliberately stays simple. Only one job can be active at a time.
|
|
31
|
+
Features such as billing calculations, notes, hierarchical projects, tags, idle
|
|
32
|
+
detection, goals, configuration files, and shell completions are omitted so the
|
|
33
|
+
tool remains a focused Unix-style utility: easy to understand, quick to use with
|
|
34
|
+
short commands, and simple to combine with other programs through its clean,
|
|
35
|
+
well-formatted output.
|
|
36
|
+
|
|
37
|
+
A simple example shows creating a job for the first time, starting time tracking
|
|
38
|
+
against that job, and then stopping the work over an hour later:
|
|
39
|
+
```bash
|
|
40
|
+
> dey -j meetings
|
|
41
|
+
New job "meetings" created.
|
|
42
|
+
> dey -t
|
|
43
|
+
00:00 | 07:42 - meetings
|
|
44
|
+
> dey -t
|
|
45
|
+
01:05 | 07:42 - 08:47 meetings
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
# Data Storage
|
|
49
|
+
|
|
50
|
+
The data for the program is saved in text files at
|
|
51
|
+
|
|
52
|
+
| OS | Location |
|
|
53
|
+
| :------ | :------------------------------------------ |
|
|
54
|
+
| Windows | `%LOCALAPPDATA%\dey\` |
|
|
55
|
+
| Linux | `$XDG_CONFIG_HOME/dey/` or `~/.config/dey/` |
|
|
56
|
+
| macOS | `~/.config/dey/` |
|
|
57
|
+
|
|
58
|
+
The `jobs.txt` file stores definitions of jobs:
|
|
59
|
+
```
|
|
60
|
+
a meetings
|
|
61
|
+
a permissive vacation
|
|
62
|
+
a permissive sickness
|
|
63
|
+
i Project X
|
|
64
|
+
```
|
|
65
|
+
Each job is defined with an ID (the row number in the file), an active, `a`, or
|
|
66
|
+
inactive, `i`, flag, and a label. The inactive flag hides the job from searches
|
|
67
|
+
when starting work on a job; it does not hide the history of work done for those
|
|
68
|
+
jobs. The jobs are in the order they were created.
|
|
69
|
+
|
|
70
|
+
The `logs.txt` file stores the work done, called "logs":
|
|
71
|
+
```
|
|
72
|
+
20260919 07:31 0001 09:22
|
|
73
|
+
20260919 10:03 0003 13:45
|
|
74
|
+
20260920 08:10 0001 10:50
|
|
75
|
+
20260926 08:30 0002
|
|
76
|
+
```
|
|
77
|
+
Each log contains a date represented as an integer in `YYYYMMDD` format, a start
|
|
78
|
+
time, a job ID, and a stop time. Times are in 24-hour format. Job IDs are
|
|
79
|
+
four-digit integers, which means up to 9999 different jobs can exist. A missing
|
|
80
|
+
stop time indicates that the log is currently active. Times are recorded to the
|
|
81
|
+
nearest minute; finer precision is omitted because minute precision introduces
|
|
82
|
+
only a zero-bias error, and many organizations do not require accuracy beyond
|
|
83
|
+
one-tenth of an hour.
|
|
84
|
+
|
|
85
|
+
The time intervals of different logs cannot overlap, so at any given moment,
|
|
86
|
+
work can be performed on only one job. As a consequence, no more than one log
|
|
87
|
+
may have a missing stop time because it is current. A log cannot span more than
|
|
88
|
+
one day. At the latest, it must end by 23:59. Consequently, no date arithmetic
|
|
89
|
+
is performed. Logs are listed in the order they were created, which may differ
|
|
90
|
+
from their chronological order.
|
|
91
|
+
|
|
92
|
+
Both the `jobs` file and the `logs` file have been designed so that in most
|
|
93
|
+
cases, a full rewrite of the file is not necessary. Instead, a new job or log
|
|
94
|
+
can be appended to the corresponding file. Though negligible anyway, this does
|
|
95
|
+
reduce processing time and wear on solid state discs. It is not intended that
|
|
96
|
+
the user ever directly modify these files; if you do, be very careful not to
|
|
97
|
+
corrupt the format.
|
|
98
|
+
|
|
99
|
+
If full editing ability were supported, a log ID would need to accompany each
|
|
100
|
+
log in order to address the specific log. Start and stop times would need to be
|
|
101
|
+
directly specified. Even an interactive interface for editing would be
|
|
102
|
+
preferable. These are all directions that would take away from the simplicity of
|
|
103
|
+
this program. Therefore, what is not supported is the ability to edit any
|
|
104
|
+
arbitrary log, besides the last. Consequently, it is the responsibility of the
|
|
105
|
+
user to pay attention when entering logs and not create the occasion for editing
|
|
106
|
+
logs several entries prior. The last entry can be modified, but anything prior
|
|
107
|
+
must be modified by undoing entries. That said, the logs file is formatted such
|
|
108
|
+
that it is not too difficult to directly edit, and the line numbers beside the
|
|
109
|
+
jobs and visible with a code editor correspond to the job IDs.
|
|
110
|
+
|
|
111
|
+
# Interface
|
|
112
|
+
|
|
113
|
+
Just the name of the program prints the status:
|
|
114
|
+
```bash
|
|
115
|
+
> dey
|
|
116
|
+
07:32 | 14:10 - 15:05 meetings
|
|
117
|
+
> dey
|
|
118
|
+
07:32 | 14:10 - meetings
|
|
119
|
+
```
|
|
120
|
+
This shows the total time worked for the present day, the start and stop times
|
|
121
|
+
and the job label of the latest log. If the latest log is current, nothing is
|
|
122
|
+
printed in place of the stop time. If no logs exist for the present day, a
|
|
123
|
+
statement to this effect is output.
|
|
124
|
+
|
|
125
|
+
Additional functionality is available with the following command arguments (flag
|
|
126
|
+
letters preceded by a dash) and their optional tails (text following the
|
|
127
|
+
arguments):
|
|
128
|
+
|
|
129
|
+
| Arguments | Description |
|
|
130
|
+
| :------------------------- | :----------------------------------- |
|
|
131
|
+
| `-l {label}` | List all active jobs matching label |
|
|
132
|
+
| `-L {label}` | List all jobs matching label |
|
|
133
|
+
| `-j {label} {label}` | Create job, rename job |
|
|
134
|
+
| `-i {label}` | Make job active job inactive |
|
|
135
|
+
| `-a {label}` | Make job inactive job active |
|
|
136
|
+
| | |
|
|
137
|
+
| `-t {time} {date} {label}` | Toggle time or switch active job |
|
|
138
|
+
| `-e {time} {label}` | Edit time or job of last entry |
|
|
139
|
+
| `-u {integer}` | Undo last log entries (default to 1) |
|
|
140
|
+
| | |
|
|
141
|
+
| `-d {date} {label}` | Day report (default to recent date) |
|
|
142
|
+
| `-w {weeks} {label}` | Week report (default to recent week) |
|
|
143
|
+
| | |
|
|
144
|
+
| `-h` | Print command help |
|
|
145
|
+
|
|
146
|
+
A `date` is entered in the format `YYYY-MM-DD` or `YY-MM-DD`. Time is entered in
|
|
147
|
+
the format `HH:MM`. Each argument is a standalone instruction that does not
|
|
148
|
+
depend on any other argument. Multiple command arguments can be given in a
|
|
149
|
+
single terminal command and they will be executed in the order they are written.
|
|
150
|
+
|
|
151
|
+
## Jobs
|
|
152
|
+
|
|
153
|
+
### List Jobs
|
|
154
|
+
|
|
155
|
+
The list of existing active jobs can be printed by entering the `-l` flag
|
|
156
|
+
without any job labels. This will print all the jobs in alphabetical order:
|
|
157
|
+
```bash
|
|
158
|
+
> dey -l
|
|
159
|
+
meetings
|
|
160
|
+
permissive sickness
|
|
161
|
+
permissive vacation
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
The list can be narrowed down by entering part of a job label after the flag:
|
|
165
|
+
```bash
|
|
166
|
+
> dey -l perm
|
|
167
|
+
permissive sickness
|
|
168
|
+
permissive vacation
|
|
169
|
+
```
|
|
170
|
+
All string matching to job labels is case-insensitive.
|
|
171
|
+
|
|
172
|
+
All jobs including inactive ones can be listed with the `-L` flag:
|
|
173
|
+
```bash
|
|
174
|
+
> dey -L
|
|
175
|
+
meetings
|
|
176
|
+
permissive sickness
|
|
177
|
+
permissive vacation
|
|
178
|
+
Project X
|
|
179
|
+
```
|
|
180
|
+
The inactive jobs are marked in gray.
|
|
181
|
+
|
|
182
|
+
### Create a Job
|
|
183
|
+
|
|
184
|
+
A new job can be defined with the `-j` argument followed by the job label:
|
|
185
|
+
```bash
|
|
186
|
+
> dey -j Clean-up
|
|
187
|
+
New job "Clean-up" created.
|
|
188
|
+
```
|
|
189
|
+
If a job by that exact name (using case-insensitive matching) already exists,
|
|
190
|
+
the command will be rejected.
|
|
191
|
+
|
|
192
|
+
### Rename a Job
|
|
193
|
+
|
|
194
|
+
An active job can be renamed by adding a second string:
|
|
195
|
+
```bash
|
|
196
|
+
> dey -j Clean-up Cleanup
|
|
197
|
+
Job "Clean-up" renamed to "Cleanup".
|
|
198
|
+
```
|
|
199
|
+
When searching for matches on the first string, a partial match will be
|
|
200
|
+
accepted. For example, `vaca` would match `permissive vacation`. If no match or
|
|
201
|
+
more than one match can be found, the command will be rejected. If the second
|
|
202
|
+
string fully matches an existing job label, the command will be rejected.
|
|
203
|
+
|
|
204
|
+
Renaming an inactive job requires first making it active.
|
|
205
|
+
|
|
206
|
+
### Active and Inactive Jobs
|
|
207
|
+
|
|
208
|
+
An active job can be made inactive so that it no longer is chosen as a valid
|
|
209
|
+
match to new work by using the `-i` flag:
|
|
210
|
+
```bash
|
|
211
|
+
> dey -i Project\ X
|
|
212
|
+
"Project X" is now inactive.
|
|
213
|
+
```
|
|
214
|
+
An inactive job can be made active by using the `-a` flag:
|
|
215
|
+
```bash
|
|
216
|
+
> dey -a Project\ X
|
|
217
|
+
"Project X" is now active.
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### Job Aliases (*not implemented*)
|
|
221
|
+
|
|
222
|
+
A job can have an alias (or description) by appending the extra text to the job
|
|
223
|
+
name separated by a colon:
|
|
224
|
+
```bash
|
|
225
|
+
> dey -j "Project X: Hyper-engine research"
|
|
226
|
+
```
|
|
227
|
+
This is useful when printing reports. Reports will list the names of projects.
|
|
228
|
+
Because many projects can lead to very similar names which can make entering
|
|
229
|
+
totals into official time-reporting software error-prone, the print feature will
|
|
230
|
+
emphasize those parts of the names which are unique. However, the alias of the
|
|
231
|
+
name will never be included in the emphasis because that part will never be used
|
|
232
|
+
in reporting. That said, job searches can still match to the alias.
|
|
233
|
+
|
|
234
|
+
## Toggle Clock
|
|
235
|
+
|
|
236
|
+
### Without Time
|
|
237
|
+
|
|
238
|
+
Time tracking is toggled using the `-t` argument:
|
|
239
|
+
```bash
|
|
240
|
+
> dey -t
|
|
241
|
+
00:18 | 07:42 - Project X
|
|
242
|
+
```
|
|
243
|
+
This will start a log if none is current or end a log if one is current. The
|
|
244
|
+
status will be automatically printed to give confirmation. The simplicity of not
|
|
245
|
+
specifying whether the time is a start or stop means there can be only one
|
|
246
|
+
active log at a time.
|
|
247
|
+
|
|
248
|
+
### With Time
|
|
249
|
+
|
|
250
|
+
By default, the current time is used, but any time can be explicitly specified
|
|
251
|
+
after the `-t` argument:
|
|
252
|
+
```bash
|
|
253
|
+
> dey -t 07:45
|
|
254
|
+
00:15 | 07:45 - Project X
|
|
255
|
+
```
|
|
256
|
+
This will mark the start or stop of a log with that time. If a new start or stop
|
|
257
|
+
time overlaps with any other log of the same day, the command will be rejected
|
|
258
|
+
and an explanation will be printed. So, giving a stop time that comes before the
|
|
259
|
+
start time of the same log will be rejected and an explanation will be printed.
|
|
260
|
+
|
|
261
|
+
Only one current log is allowed at a time. This is why the interface does not
|
|
262
|
+
provide separate start and stop commands. So, if a log is current (has no stop
|
|
263
|
+
time) another log cannot be started. Instead, if the time is after the start
|
|
264
|
+
time of the current log, the new time will be used as the stop time of the
|
|
265
|
+
current log.
|
|
266
|
+
|
|
267
|
+
It is possible to forget to stop a log at the end of the day. So, the next day
|
|
268
|
+
when a time is given, it will be used as the stop time of yesterday's log. If
|
|
269
|
+
the stop time is before the log's start time, the command will be rejected.
|
|
270
|
+
Clocking out will only apply to the same day as the start of the current log.
|
|
271
|
+
This means you can clock out by entering something like `dey -t 17:00` and this
|
|
272
|
+
will apply to the day the current log was started. The program will not mark the
|
|
273
|
+
log as continuing into the next day.
|
|
274
|
+
|
|
275
|
+
Because logs can be defined with specific times (other than the present), they
|
|
276
|
+
can be created out of order. The log file is not sorted in chronological order.
|
|
277
|
+
This is a deliberate choice to support undoing actions in the order they were
|
|
278
|
+
commanded.
|
|
279
|
+
|
|
280
|
+
If an active log was started on a prior day, the date must be specified. A log
|
|
281
|
+
cannot span across dates.
|
|
282
|
+
|
|
283
|
+
### With Date
|
|
284
|
+
|
|
285
|
+
By default, the current day is used, but any date can be specified explicitly
|
|
286
|
+
after the `-t` argument:
|
|
287
|
+
```bash
|
|
288
|
+
> dey -t 07:45 26-09-17
|
|
289
|
+
```
|
|
290
|
+
The format for dates is either `26-09-07` or `2026-09-07`.
|
|
291
|
+
|
|
292
|
+
### With Job Label
|
|
293
|
+
|
|
294
|
+
By default, the job of the last log is the assumed job for a new log. However,
|
|
295
|
+
any job can be specified:
|
|
296
|
+
```bash
|
|
297
|
+
> dey -t meetings
|
|
298
|
+
00:18 | 07:42 - meetings
|
|
299
|
+
```
|
|
300
|
+
If no log is current, the job specified is used as the job of the new log. If a
|
|
301
|
+
log is current, the current time or the time provided is used to stop the
|
|
302
|
+
current log and to create a new log and the specified job is used for the new
|
|
303
|
+
log. This makes it easy to switch jobs without having to explicitly stop the
|
|
304
|
+
current log and start another. If the specified job does not match any
|
|
305
|
+
previously-defined jobs, the command will be rejected.
|
|
306
|
+
|
|
307
|
+
### Undo Last Entry (*not implemented*)
|
|
308
|
+
|
|
309
|
+
The last entry (start or stop or a log) can be undone with the `-u` argument:
|
|
310
|
+
```bash
|
|
311
|
+
> dey -u
|
|
312
|
+
No logs for today.
|
|
313
|
+
```
|
|
314
|
+
Multiple entries can be undone at once by providing an integer.
|
|
315
|
+
|
|
316
|
+
### Edit Last Entry (*not implemented*)
|
|
317
|
+
|
|
318
|
+
The last log entry (start time, job label, or stop time) can be edited with
|
|
319
|
+
the `-e` argument. So, if a log is current, the `-e` command can be used to
|
|
320
|
+
change the start time:
|
|
321
|
+
```bash
|
|
322
|
+
> dey -e 07:45
|
|
323
|
+
00:15 | 07:45 - Project X
|
|
324
|
+
```
|
|
325
|
+
Providing a job label will change the job of the last entry.
|
|
326
|
+
```bash
|
|
327
|
+
> dey -e meetings
|
|
328
|
+
00:18 | 07:42 - meetings
|
|
329
|
+
```
|
|
330
|
+
Both a time and a job label can be specified together.
|
|
331
|
+
|
|
332
|
+
## Reports
|
|
333
|
+
|
|
334
|
+
### Day Reports (*partially implemented*)
|
|
335
|
+
|
|
336
|
+
The day report shows the date of the last log and a color-coded graph of that
|
|
337
|
+
day's work. This is followed by that day's logs, each preceded by the
|
|
338
|
+
corresponding color-coding. Finally, the total hours for the day are printed:
|
|
339
|
+
```bash
|
|
340
|
+
> dey -d
|
|
341
|
+
2026-11-09 ================== ===================
|
|
342
|
+
= 01:15 (1.25) permissive sick
|
|
343
|
+
= 04:38 (4.63) Project X
|
|
344
|
+
05:53 (5.88)
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
Colors are chosen from a subset of the 8-bit ANSI-escape-code colors based on
|
|
348
|
+
the order the jobs first appeared in the day. (Only 8-bit colors are used
|
|
349
|
+
because most terminal emulators support those but not all terminal emulators
|
|
350
|
+
support millions of colors.) Depending on the start and stop times for the day
|
|
351
|
+
and the column width of the present output stream, each character in the graph
|
|
352
|
+
corresponds to a 5, 10, 15, 20, or 30 minute increment. The start of the bar
|
|
353
|
+
corresponds to the beginning of the first log of the day and the end corresponds
|
|
354
|
+
to the end of the last or present if a log is current.
|
|
355
|
+
|
|
356
|
+
Because the day summary can accept a date, any past day can be reported. If a
|
|
357
|
+
date is provided (in the format `26-09-07` or `2026-09-07`) the summary of that
|
|
358
|
+
day will be printed. If a job label is provided as in `dey -d meetings`, the
|
|
359
|
+
summary of just that job (or any job to which the text substring matches) for
|
|
360
|
+
the current date will be printed. These two options can be combined as in `dey
|
|
361
|
+
-d 26-09-07 meetings` to print a report of just that job for that date. The
|
|
362
|
+
colors chosen will be the same as if all the jobs for the day were printed.
|
|
363
|
+
|
|
364
|
+
### Week Reports (*not implemented*)
|
|
365
|
+
|
|
366
|
+
The week report (`dey -w`) aligns with the beginning of a week, not the current
|
|
367
|
+
day. For example, if the current day is Wednesday, the current week would be
|
|
368
|
+
from Sunday of that week to Wednesday, not the past seven days. The purpose of
|
|
369
|
+
the week report is to show the total hours worked per day, per job, and for the
|
|
370
|
+
week. The report is printed in a markdown-compatible format:
|
|
371
|
+
```bash
|
|
372
|
+
> dey -w
|
|
373
|
+
Total | 09-06 | 09-07 | 09-09 | 09-10 | 09-11 | Job
|
|
374
|
+
:---: | :---: | :---: | :---: | :---: | :---: | :---
|
|
375
|
+
13:15 | 02:45 | 08:00 | 02:00 | 00:00 | 00:30 | Meetings
|
|
376
|
+
16:30 | 03:30 | 00:00 | 05:00 | 02:00 | 06:00 | Documentation
|
|
377
|
+
10:15 | 02:00 | 00:00 | 01:30 | 05:30 | 01:15 | Education
|
|
378
|
+
--- | --- | --- | --- | --- | --- |
|
|
379
|
+
40:00 | 08:15 | 08:00 | 08:30 | 07:30 | 07:45 |
|
|
380
|
+
```
|
|
381
|
+
More weeks can be specified with a number after the `-w` argument flag. The
|
|
382
|
+
additional weeks will be printed as separate tables in chronological order.
|
|
383
|
+
|
|
384
|
+
If a job label is provided, just like the day report, only logs matching that
|
|
385
|
+
search will be printed. Because of substring search, multiple job labels can be
|
|
386
|
+
matches.
|
|
387
|
+
|
|
388
|
+
# Alternatives
|
|
389
|
+
|
|
390
|
+
There are several alternatives, but I believe none approach this problem with
|
|
391
|
+
the same level of simplicity and succinctness or brevity as `dey`.
|
|
392
|
+
|
|
393
|
+
- [bartib][2]
|
|
394
|
+
- [timetrace][3]
|
|
395
|
+
- [timetrap][4]
|
|
396
|
+
- [timewarrior][5]
|
|
397
|
+
- [tmpo][6]
|
|
398
|
+
- [watson][7]
|
|
399
|
+
- [zeit][8]
|
|
400
|
+
|
|
401
|
+
|
|
402
|
+
[1]:https://americanhistory.si.edu/collections/object/nmah_856741
|
|
403
|
+
[2]:https://github.com/nikolassv/bartib
|
|
404
|
+
[3]:https://github.com/dominikbraun/timetrace
|
|
405
|
+
[4]:https://github.com/samg/timetrap
|
|
406
|
+
[5]:https://github.com/gothenburgbitfactory/timewarrior
|
|
407
|
+
[6]:https://github.com/DylanDevelops/tmpo
|
|
408
|
+
[7]:https://github.com/jazzband/Watson
|
|
409
|
+
[8]:https://github.com/mrusme/zeit
|
|
@@ -322,29 +322,25 @@ Both a time and a job label can be specified together.
|
|
|
322
322
|
|
|
323
323
|
### Day Reports (*partially implemented*)
|
|
324
324
|
|
|
325
|
-
The day report shows the date of the last log
|
|
326
|
-
work
|
|
327
|
-
|
|
328
|
-
not support ANSI escape codes, letters are used instead:
|
|
325
|
+
The day report shows the date of the last log and a color-coded graph of that
|
|
326
|
+
day's work. This is followed by that day's logs, each preceded by the
|
|
327
|
+
corresponding color-coding. Finally, the total hours for the day are printed:
|
|
329
328
|
```bash
|
|
330
329
|
> dey -d
|
|
331
|
-
2026-09
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
c 03:59 | meetings
|
|
330
|
+
2026-11-09 ================== ===================
|
|
331
|
+
= 01:15 (1.25) permissive sick
|
|
332
|
+
= 04:38 (4.63) Project X
|
|
333
|
+
05:53 (5.88)
|
|
336
334
|
```
|
|
337
335
|
|
|
338
336
|
Colors are chosen from a subset of the 8-bit ANSI-escape-code colors based on
|
|
339
337
|
the order the jobs first appeared in the day. (Only 8-bit colors are used
|
|
340
338
|
because most terminal emulators support those but not all terminal emulators
|
|
341
|
-
support millions of colors.)
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
of the day and the end corresponds to the end of the last or present if a log is
|
|
347
|
-
current.
|
|
339
|
+
support millions of colors.) Depending on the start and stop times for the day
|
|
340
|
+
and the column width of the present output stream, each character in the graph
|
|
341
|
+
corresponds to a 5, 10, 15, 20, or 30 minute increment. The start of the bar
|
|
342
|
+
corresponds to the beginning of the first log of the day and the end corresponds
|
|
343
|
+
to the end of the last or present if a log is current.
|
|
348
344
|
|
|
349
345
|
Because the day summary can accept a date, any past day can be reported. If a
|
|
350
346
|
date is provided (in the format `26-09-07` or `2026-09-07`) the summary of that
|
|
@@ -25,6 +25,7 @@ RESET = "\x1b[0m"
|
|
|
25
25
|
|
|
26
26
|
# Constants
|
|
27
27
|
N_GIVE_UP = 100
|
|
28
|
+
BAR_CHAR = '='
|
|
28
29
|
|
|
29
30
|
# -----------------
|
|
30
31
|
# File IO functions
|
|
@@ -118,8 +119,9 @@ def dump_logs(path: str, logs: list):
|
|
|
118
119
|
|
|
119
120
|
def print_status(total, start, stop, job, possible_stop):
|
|
120
121
|
total_hr, total_min = divmod(total, 60)
|
|
122
|
+
total_frac = round(total_hr + total_min/60.0, 2)
|
|
121
123
|
start_hr, start_min = divmod(start, 60)
|
|
122
|
-
print(f" {total_hr:02d}:{total_min:02d} | ", end="")
|
|
124
|
+
print(f" {total_hr:02d}:{total_min:02d} ({total_frac:.2f}) | ", end="")
|
|
123
125
|
print(f"{start_hr:02d}:{start_min:02d} - ", end="")
|
|
124
126
|
if stop < 0:
|
|
125
127
|
stop_hr, stop_min = divmod(possible_stop, 60)
|
|
@@ -645,8 +647,13 @@ def report_day(jobs, logs, tails):
|
|
|
645
647
|
continue
|
|
646
648
|
job_query = tail
|
|
647
649
|
|
|
648
|
-
# Get the logs for the specified date
|
|
650
|
+
# Get the logs for the specified date.
|
|
649
651
|
logs_on_date = find_logs_on_date(logs, date)
|
|
652
|
+
if not logs_on_date:
|
|
653
|
+
print(" No work to report for this day.")
|
|
654
|
+
return
|
|
655
|
+
|
|
656
|
+
# Sort the logs and conclude the active log.
|
|
650
657
|
logs_sorted = sort_logs(logs_on_date)
|
|
651
658
|
logs_concluded, possible_stop = conclude_active(logs_sorted)
|
|
652
659
|
|
|
@@ -669,13 +676,53 @@ def report_day(jobs, logs, tails):
|
|
|
669
676
|
idx = jobs_unique.index(log[2])
|
|
670
677
|
totals_unique[idx] += log[3] - log[1]
|
|
671
678
|
|
|
679
|
+
# Initialize bar graph.
|
|
680
|
+
N_chars = 60
|
|
681
|
+
increments = [5, 10, 15, 20, 30]
|
|
682
|
+
for inc in increments:
|
|
683
|
+
if span <= inc*N_chars:
|
|
684
|
+
break
|
|
685
|
+
bar = [0]*N_chars
|
|
686
|
+
|
|
687
|
+
# Fill bar graph.
|
|
688
|
+
for log in logs_concluded:
|
|
689
|
+
idx = jobs_unique.index(log[2])
|
|
690
|
+
ia = round((log[1] - logs_concluded[0][1]) / inc)
|
|
691
|
+
ib = round((log[3] - logs_concluded[0][1]) / inc)
|
|
692
|
+
for i in range(ia, ib + 1):
|
|
693
|
+
bar[i] = (idx % 6) + 1
|
|
694
|
+
|
|
695
|
+
# Translate the bar graph.
|
|
696
|
+
s = ""
|
|
697
|
+
b_last = 0
|
|
698
|
+
for b in bar:
|
|
699
|
+
if b != b_last:
|
|
700
|
+
s += RESET
|
|
701
|
+
if b > 0:
|
|
702
|
+
s += f"\x1b[{90 + b}m"
|
|
703
|
+
if b == 0:
|
|
704
|
+
s += " "
|
|
705
|
+
else:
|
|
706
|
+
s += BAR_CHAR
|
|
707
|
+
b_last = b
|
|
708
|
+
s += RESET
|
|
709
|
+
|
|
710
|
+
# Print the bar graph.
|
|
711
|
+
y, res = divmod(date, 10000)
|
|
712
|
+
m, d = divmod(res, 100)
|
|
713
|
+
print(f" {y:04d}-{m:02d}-{d:02d} {s}")
|
|
714
|
+
|
|
672
715
|
# Print the totals.
|
|
673
716
|
for j in range(J):
|
|
674
717
|
hu, mu = divmod(totals_unique[j], 60)
|
|
718
|
+
hu_frac = round(hu + mu/60.0, 2)
|
|
675
719
|
label = jobs[jobs_unique[j] - 1][1]
|
|
676
|
-
print(f" {
|
|
720
|
+
print(f" \x1b[{90 + j + 1}m{BAR_CHAR}{RESET}"
|
|
721
|
+
+ f" {hu:02d}:{mu:02d} ({hu_frac:.2f})"
|
|
722
|
+
+ f" {label}")
|
|
677
723
|
hn, mn = divmod(net, 60)
|
|
678
|
-
|
|
724
|
+
hn_frac = round(hn + mn/60.0, 2)
|
|
725
|
+
print(f" {hn:02d}:{mn:02d} ({hn_frac:.2f})")
|
|
679
726
|
|
|
680
727
|
|
|
681
728
|
def report_week(jobs, logs, tails):
|
|
@@ -0,0 +1,409 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: dey
|
|
3
|
+
Version: 0.2.2
|
|
4
|
+
Summary: Terminal time tracker
|
|
5
|
+
Author-email: David Woodburn <david.woodburn@icloud.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Requires-Python: >=3.7
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Dynamic: license-file
|
|
11
|
+
|
|
12
|
+
# Introduction
|
|
13
|
+
|
|
14
|
+
`dey` is a terminal-based time tracker for logging work hours against named
|
|
15
|
+
jobs.
|
|
16
|
+
|
|
17
|
+
The name comes from the [Alexander Dey Time Register Clock][1] (1888), an early
|
|
18
|
+
punch-clock that recorded employee hours on a paper roll. Like its namesake,
|
|
19
|
+
`dey` uses a simple punch-in, punch-out model: start a timer against a job, stop
|
|
20
|
+
it later. You can also backfill entries for past times.
|
|
21
|
+
|
|
22
|
+
Using a spreadsheet to track work hours is cumbersome: Excel is slow to open,
|
|
23
|
+
times and dates must be entered manually, multiple jobs create an unwieldy
|
|
24
|
+
number of columns, and generating summaries is complicated. This program offers
|
|
25
|
+
a simple terminal-based alternative. It automatically records the current date
|
|
26
|
+
and time, resolves short job-name fragments by substring matching, and produces
|
|
27
|
+
clear daily and weekly summaries that can be filtered the same way. A single
|
|
28
|
+
command also lets you undo the last entry, adjust its time, or change its job.
|
|
29
|
+
|
|
30
|
+
The design deliberately stays simple. Only one job can be active at a time.
|
|
31
|
+
Features such as billing calculations, notes, hierarchical projects, tags, idle
|
|
32
|
+
detection, goals, configuration files, and shell completions are omitted so the
|
|
33
|
+
tool remains a focused Unix-style utility: easy to understand, quick to use with
|
|
34
|
+
short commands, and simple to combine with other programs through its clean,
|
|
35
|
+
well-formatted output.
|
|
36
|
+
|
|
37
|
+
A simple example shows creating a job for the first time, starting time tracking
|
|
38
|
+
against that job, and then stopping the work over an hour later:
|
|
39
|
+
```bash
|
|
40
|
+
> dey -j meetings
|
|
41
|
+
New job "meetings" created.
|
|
42
|
+
> dey -t
|
|
43
|
+
00:00 | 07:42 - meetings
|
|
44
|
+
> dey -t
|
|
45
|
+
01:05 | 07:42 - 08:47 meetings
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
# Data Storage
|
|
49
|
+
|
|
50
|
+
The data for the program is saved in text files at
|
|
51
|
+
|
|
52
|
+
| OS | Location |
|
|
53
|
+
| :------ | :------------------------------------------ |
|
|
54
|
+
| Windows | `%LOCALAPPDATA%\dey\` |
|
|
55
|
+
| Linux | `$XDG_CONFIG_HOME/dey/` or `~/.config/dey/` |
|
|
56
|
+
| macOS | `~/.config/dey/` |
|
|
57
|
+
|
|
58
|
+
The `jobs.txt` file stores definitions of jobs:
|
|
59
|
+
```
|
|
60
|
+
a meetings
|
|
61
|
+
a permissive vacation
|
|
62
|
+
a permissive sickness
|
|
63
|
+
i Project X
|
|
64
|
+
```
|
|
65
|
+
Each job is defined with an ID (the row number in the file), an active, `a`, or
|
|
66
|
+
inactive, `i`, flag, and a label. The inactive flag hides the job from searches
|
|
67
|
+
when starting work on a job; it does not hide the history of work done for those
|
|
68
|
+
jobs. The jobs are in the order they were created.
|
|
69
|
+
|
|
70
|
+
The `logs.txt` file stores the work done, called "logs":
|
|
71
|
+
```
|
|
72
|
+
20260919 07:31 0001 09:22
|
|
73
|
+
20260919 10:03 0003 13:45
|
|
74
|
+
20260920 08:10 0001 10:50
|
|
75
|
+
20260926 08:30 0002
|
|
76
|
+
```
|
|
77
|
+
Each log contains a date represented as an integer in `YYYYMMDD` format, a start
|
|
78
|
+
time, a job ID, and a stop time. Times are in 24-hour format. Job IDs are
|
|
79
|
+
four-digit integers, which means up to 9999 different jobs can exist. A missing
|
|
80
|
+
stop time indicates that the log is currently active. Times are recorded to the
|
|
81
|
+
nearest minute; finer precision is omitted because minute precision introduces
|
|
82
|
+
only a zero-bias error, and many organizations do not require accuracy beyond
|
|
83
|
+
one-tenth of an hour.
|
|
84
|
+
|
|
85
|
+
The time intervals of different logs cannot overlap, so at any given moment,
|
|
86
|
+
work can be performed on only one job. As a consequence, no more than one log
|
|
87
|
+
may have a missing stop time because it is current. A log cannot span more than
|
|
88
|
+
one day. At the latest, it must end by 23:59. Consequently, no date arithmetic
|
|
89
|
+
is performed. Logs are listed in the order they were created, which may differ
|
|
90
|
+
from their chronological order.
|
|
91
|
+
|
|
92
|
+
Both the `jobs` file and the `logs` file have been designed so that in most
|
|
93
|
+
cases, a full rewrite of the file is not necessary. Instead, a new job or log
|
|
94
|
+
can be appended to the corresponding file. Though negligible anyway, this does
|
|
95
|
+
reduce processing time and wear on solid state discs. It is not intended that
|
|
96
|
+
the user ever directly modify these files; if you do, be very careful not to
|
|
97
|
+
corrupt the format.
|
|
98
|
+
|
|
99
|
+
If full editing ability were supported, a log ID would need to accompany each
|
|
100
|
+
log in order to address the specific log. Start and stop times would need to be
|
|
101
|
+
directly specified. Even an interactive interface for editing would be
|
|
102
|
+
preferable. These are all directions that would take away from the simplicity of
|
|
103
|
+
this program. Therefore, what is not supported is the ability to edit any
|
|
104
|
+
arbitrary log, besides the last. Consequently, it is the responsibility of the
|
|
105
|
+
user to pay attention when entering logs and not create the occasion for editing
|
|
106
|
+
logs several entries prior. The last entry can be modified, but anything prior
|
|
107
|
+
must be modified by undoing entries. That said, the logs file is formatted such
|
|
108
|
+
that it is not too difficult to directly edit, and the line numbers beside the
|
|
109
|
+
jobs and visible with a code editor correspond to the job IDs.
|
|
110
|
+
|
|
111
|
+
# Interface
|
|
112
|
+
|
|
113
|
+
Just the name of the program prints the status:
|
|
114
|
+
```bash
|
|
115
|
+
> dey
|
|
116
|
+
07:32 | 14:10 - 15:05 meetings
|
|
117
|
+
> dey
|
|
118
|
+
07:32 | 14:10 - meetings
|
|
119
|
+
```
|
|
120
|
+
This shows the total time worked for the present day, the start and stop times
|
|
121
|
+
and the job label of the latest log. If the latest log is current, nothing is
|
|
122
|
+
printed in place of the stop time. If no logs exist for the present day, a
|
|
123
|
+
statement to this effect is output.
|
|
124
|
+
|
|
125
|
+
Additional functionality is available with the following command arguments (flag
|
|
126
|
+
letters preceded by a dash) and their optional tails (text following the
|
|
127
|
+
arguments):
|
|
128
|
+
|
|
129
|
+
| Arguments | Description |
|
|
130
|
+
| :------------------------- | :----------------------------------- |
|
|
131
|
+
| `-l {label}` | List all active jobs matching label |
|
|
132
|
+
| `-L {label}` | List all jobs matching label |
|
|
133
|
+
| `-j {label} {label}` | Create job, rename job |
|
|
134
|
+
| `-i {label}` | Make job active job inactive |
|
|
135
|
+
| `-a {label}` | Make job inactive job active |
|
|
136
|
+
| | |
|
|
137
|
+
| `-t {time} {date} {label}` | Toggle time or switch active job |
|
|
138
|
+
| `-e {time} {label}` | Edit time or job of last entry |
|
|
139
|
+
| `-u {integer}` | Undo last log entries (default to 1) |
|
|
140
|
+
| | |
|
|
141
|
+
| `-d {date} {label}` | Day report (default to recent date) |
|
|
142
|
+
| `-w {weeks} {label}` | Week report (default to recent week) |
|
|
143
|
+
| | |
|
|
144
|
+
| `-h` | Print command help |
|
|
145
|
+
|
|
146
|
+
A `date` is entered in the format `YYYY-MM-DD` or `YY-MM-DD`. Time is entered in
|
|
147
|
+
the format `HH:MM`. Each argument is a standalone instruction that does not
|
|
148
|
+
depend on any other argument. Multiple command arguments can be given in a
|
|
149
|
+
single terminal command and they will be executed in the order they are written.
|
|
150
|
+
|
|
151
|
+
## Jobs
|
|
152
|
+
|
|
153
|
+
### List Jobs
|
|
154
|
+
|
|
155
|
+
The list of existing active jobs can be printed by entering the `-l` flag
|
|
156
|
+
without any job labels. This will print all the jobs in alphabetical order:
|
|
157
|
+
```bash
|
|
158
|
+
> dey -l
|
|
159
|
+
meetings
|
|
160
|
+
permissive sickness
|
|
161
|
+
permissive vacation
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
The list can be narrowed down by entering part of a job label after the flag:
|
|
165
|
+
```bash
|
|
166
|
+
> dey -l perm
|
|
167
|
+
permissive sickness
|
|
168
|
+
permissive vacation
|
|
169
|
+
```
|
|
170
|
+
All string matching to job labels is case-insensitive.
|
|
171
|
+
|
|
172
|
+
All jobs including inactive ones can be listed with the `-L` flag:
|
|
173
|
+
```bash
|
|
174
|
+
> dey -L
|
|
175
|
+
meetings
|
|
176
|
+
permissive sickness
|
|
177
|
+
permissive vacation
|
|
178
|
+
Project X
|
|
179
|
+
```
|
|
180
|
+
The inactive jobs are marked in gray.
|
|
181
|
+
|
|
182
|
+
### Create a Job
|
|
183
|
+
|
|
184
|
+
A new job can be defined with the `-j` argument followed by the job label:
|
|
185
|
+
```bash
|
|
186
|
+
> dey -j Clean-up
|
|
187
|
+
New job "Clean-up" created.
|
|
188
|
+
```
|
|
189
|
+
If a job by that exact name (using case-insensitive matching) already exists,
|
|
190
|
+
the command will be rejected.
|
|
191
|
+
|
|
192
|
+
### Rename a Job
|
|
193
|
+
|
|
194
|
+
An active job can be renamed by adding a second string:
|
|
195
|
+
```bash
|
|
196
|
+
> dey -j Clean-up Cleanup
|
|
197
|
+
Job "Clean-up" renamed to "Cleanup".
|
|
198
|
+
```
|
|
199
|
+
When searching for matches on the first string, a partial match will be
|
|
200
|
+
accepted. For example, `vaca` would match `permissive vacation`. If no match or
|
|
201
|
+
more than one match can be found, the command will be rejected. If the second
|
|
202
|
+
string fully matches an existing job label, the command will be rejected.
|
|
203
|
+
|
|
204
|
+
Renaming an inactive job requires first making it active.
|
|
205
|
+
|
|
206
|
+
### Active and Inactive Jobs
|
|
207
|
+
|
|
208
|
+
An active job can be made inactive so that it no longer is chosen as a valid
|
|
209
|
+
match to new work by using the `-i` flag:
|
|
210
|
+
```bash
|
|
211
|
+
> dey -i Project\ X
|
|
212
|
+
"Project X" is now inactive.
|
|
213
|
+
```
|
|
214
|
+
An inactive job can be made active by using the `-a` flag:
|
|
215
|
+
```bash
|
|
216
|
+
> dey -a Project\ X
|
|
217
|
+
"Project X" is now active.
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### Job Aliases (*not implemented*)
|
|
221
|
+
|
|
222
|
+
A job can have an alias (or description) by appending the extra text to the job
|
|
223
|
+
name separated by a colon:
|
|
224
|
+
```bash
|
|
225
|
+
> dey -j "Project X: Hyper-engine research"
|
|
226
|
+
```
|
|
227
|
+
This is useful when printing reports. Reports will list the names of projects.
|
|
228
|
+
Because many projects can lead to very similar names which can make entering
|
|
229
|
+
totals into official time-reporting software error-prone, the print feature will
|
|
230
|
+
emphasize those parts of the names which are unique. However, the alias of the
|
|
231
|
+
name will never be included in the emphasis because that part will never be used
|
|
232
|
+
in reporting. That said, job searches can still match to the alias.
|
|
233
|
+
|
|
234
|
+
## Toggle Clock
|
|
235
|
+
|
|
236
|
+
### Without Time
|
|
237
|
+
|
|
238
|
+
Time tracking is toggled using the `-t` argument:
|
|
239
|
+
```bash
|
|
240
|
+
> dey -t
|
|
241
|
+
00:18 | 07:42 - Project X
|
|
242
|
+
```
|
|
243
|
+
This will start a log if none is current or end a log if one is current. The
|
|
244
|
+
status will be automatically printed to give confirmation. The simplicity of not
|
|
245
|
+
specifying whether the time is a start or stop means there can be only one
|
|
246
|
+
active log at a time.
|
|
247
|
+
|
|
248
|
+
### With Time
|
|
249
|
+
|
|
250
|
+
By default, the current time is used, but any time can be explicitly specified
|
|
251
|
+
after the `-t` argument:
|
|
252
|
+
```bash
|
|
253
|
+
> dey -t 07:45
|
|
254
|
+
00:15 | 07:45 - Project X
|
|
255
|
+
```
|
|
256
|
+
This will mark the start or stop of a log with that time. If a new start or stop
|
|
257
|
+
time overlaps with any other log of the same day, the command will be rejected
|
|
258
|
+
and an explanation will be printed. So, giving a stop time that comes before the
|
|
259
|
+
start time of the same log will be rejected and an explanation will be printed.
|
|
260
|
+
|
|
261
|
+
Only one current log is allowed at a time. This is why the interface does not
|
|
262
|
+
provide separate start and stop commands. So, if a log is current (has no stop
|
|
263
|
+
time) another log cannot be started. Instead, if the time is after the start
|
|
264
|
+
time of the current log, the new time will be used as the stop time of the
|
|
265
|
+
current log.
|
|
266
|
+
|
|
267
|
+
It is possible to forget to stop a log at the end of the day. So, the next day
|
|
268
|
+
when a time is given, it will be used as the stop time of yesterday's log. If
|
|
269
|
+
the stop time is before the log's start time, the command will be rejected.
|
|
270
|
+
Clocking out will only apply to the same day as the start of the current log.
|
|
271
|
+
This means you can clock out by entering something like `dey -t 17:00` and this
|
|
272
|
+
will apply to the day the current log was started. The program will not mark the
|
|
273
|
+
log as continuing into the next day.
|
|
274
|
+
|
|
275
|
+
Because logs can be defined with specific times (other than the present), they
|
|
276
|
+
can be created out of order. The log file is not sorted in chronological order.
|
|
277
|
+
This is a deliberate choice to support undoing actions in the order they were
|
|
278
|
+
commanded.
|
|
279
|
+
|
|
280
|
+
If an active log was started on a prior day, the date must be specified. A log
|
|
281
|
+
cannot span across dates.
|
|
282
|
+
|
|
283
|
+
### With Date
|
|
284
|
+
|
|
285
|
+
By default, the current day is used, but any date can be specified explicitly
|
|
286
|
+
after the `-t` argument:
|
|
287
|
+
```bash
|
|
288
|
+
> dey -t 07:45 26-09-17
|
|
289
|
+
```
|
|
290
|
+
The format for dates is either `26-09-07` or `2026-09-07`.
|
|
291
|
+
|
|
292
|
+
### With Job Label
|
|
293
|
+
|
|
294
|
+
By default, the job of the last log is the assumed job for a new log. However,
|
|
295
|
+
any job can be specified:
|
|
296
|
+
```bash
|
|
297
|
+
> dey -t meetings
|
|
298
|
+
00:18 | 07:42 - meetings
|
|
299
|
+
```
|
|
300
|
+
If no log is current, the job specified is used as the job of the new log. If a
|
|
301
|
+
log is current, the current time or the time provided is used to stop the
|
|
302
|
+
current log and to create a new log and the specified job is used for the new
|
|
303
|
+
log. This makes it easy to switch jobs without having to explicitly stop the
|
|
304
|
+
current log and start another. If the specified job does not match any
|
|
305
|
+
previously-defined jobs, the command will be rejected.
|
|
306
|
+
|
|
307
|
+
### Undo Last Entry (*not implemented*)
|
|
308
|
+
|
|
309
|
+
The last entry (start or stop or a log) can be undone with the `-u` argument:
|
|
310
|
+
```bash
|
|
311
|
+
> dey -u
|
|
312
|
+
No logs for today.
|
|
313
|
+
```
|
|
314
|
+
Multiple entries can be undone at once by providing an integer.
|
|
315
|
+
|
|
316
|
+
### Edit Last Entry (*not implemented*)
|
|
317
|
+
|
|
318
|
+
The last log entry (start time, job label, or stop time) can be edited with
|
|
319
|
+
the `-e` argument. So, if a log is current, the `-e` command can be used to
|
|
320
|
+
change the start time:
|
|
321
|
+
```bash
|
|
322
|
+
> dey -e 07:45
|
|
323
|
+
00:15 | 07:45 - Project X
|
|
324
|
+
```
|
|
325
|
+
Providing a job label will change the job of the last entry.
|
|
326
|
+
```bash
|
|
327
|
+
> dey -e meetings
|
|
328
|
+
00:18 | 07:42 - meetings
|
|
329
|
+
```
|
|
330
|
+
Both a time and a job label can be specified together.
|
|
331
|
+
|
|
332
|
+
## Reports
|
|
333
|
+
|
|
334
|
+
### Day Reports (*partially implemented*)
|
|
335
|
+
|
|
336
|
+
The day report shows the date of the last log and a color-coded graph of that
|
|
337
|
+
day's work. This is followed by that day's logs, each preceded by the
|
|
338
|
+
corresponding color-coding. Finally, the total hours for the day are printed:
|
|
339
|
+
```bash
|
|
340
|
+
> dey -d
|
|
341
|
+
2026-11-09 ================== ===================
|
|
342
|
+
= 01:15 (1.25) permissive sick
|
|
343
|
+
= 04:38 (4.63) Project X
|
|
344
|
+
05:53 (5.88)
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
Colors are chosen from a subset of the 8-bit ANSI-escape-code colors based on
|
|
348
|
+
the order the jobs first appeared in the day. (Only 8-bit colors are used
|
|
349
|
+
because most terminal emulators support those but not all terminal emulators
|
|
350
|
+
support millions of colors.) Depending on the start and stop times for the day
|
|
351
|
+
and the column width of the present output stream, each character in the graph
|
|
352
|
+
corresponds to a 5, 10, 15, 20, or 30 minute increment. The start of the bar
|
|
353
|
+
corresponds to the beginning of the first log of the day and the end corresponds
|
|
354
|
+
to the end of the last or present if a log is current.
|
|
355
|
+
|
|
356
|
+
Because the day summary can accept a date, any past day can be reported. If a
|
|
357
|
+
date is provided (in the format `26-09-07` or `2026-09-07`) the summary of that
|
|
358
|
+
day will be printed. If a job label is provided as in `dey -d meetings`, the
|
|
359
|
+
summary of just that job (or any job to which the text substring matches) for
|
|
360
|
+
the current date will be printed. These two options can be combined as in `dey
|
|
361
|
+
-d 26-09-07 meetings` to print a report of just that job for that date. The
|
|
362
|
+
colors chosen will be the same as if all the jobs for the day were printed.
|
|
363
|
+
|
|
364
|
+
### Week Reports (*not implemented*)
|
|
365
|
+
|
|
366
|
+
The week report (`dey -w`) aligns with the beginning of a week, not the current
|
|
367
|
+
day. For example, if the current day is Wednesday, the current week would be
|
|
368
|
+
from Sunday of that week to Wednesday, not the past seven days. The purpose of
|
|
369
|
+
the week report is to show the total hours worked per day, per job, and for the
|
|
370
|
+
week. The report is printed in a markdown-compatible format:
|
|
371
|
+
```bash
|
|
372
|
+
> dey -w
|
|
373
|
+
Total | 09-06 | 09-07 | 09-09 | 09-10 | 09-11 | Job
|
|
374
|
+
:---: | :---: | :---: | :---: | :---: | :---: | :---
|
|
375
|
+
13:15 | 02:45 | 08:00 | 02:00 | 00:00 | 00:30 | Meetings
|
|
376
|
+
16:30 | 03:30 | 00:00 | 05:00 | 02:00 | 06:00 | Documentation
|
|
377
|
+
10:15 | 02:00 | 00:00 | 01:30 | 05:30 | 01:15 | Education
|
|
378
|
+
--- | --- | --- | --- | --- | --- |
|
|
379
|
+
40:00 | 08:15 | 08:00 | 08:30 | 07:30 | 07:45 |
|
|
380
|
+
```
|
|
381
|
+
More weeks can be specified with a number after the `-w` argument flag. The
|
|
382
|
+
additional weeks will be printed as separate tables in chronological order.
|
|
383
|
+
|
|
384
|
+
If a job label is provided, just like the day report, only logs matching that
|
|
385
|
+
search will be printed. Because of substring search, multiple job labels can be
|
|
386
|
+
matches.
|
|
387
|
+
|
|
388
|
+
# Alternatives
|
|
389
|
+
|
|
390
|
+
There are several alternatives, but I believe none approach this problem with
|
|
391
|
+
the same level of simplicity and succinctness or brevity as `dey`.
|
|
392
|
+
|
|
393
|
+
- [bartib][2]
|
|
394
|
+
- [timetrace][3]
|
|
395
|
+
- [timetrap][4]
|
|
396
|
+
- [timewarrior][5]
|
|
397
|
+
- [tmpo][6]
|
|
398
|
+
- [watson][7]
|
|
399
|
+
- [zeit][8]
|
|
400
|
+
|
|
401
|
+
|
|
402
|
+
[1]:https://americanhistory.si.edu/collections/object/nmah_856741
|
|
403
|
+
[2]:https://github.com/nikolassv/bartib
|
|
404
|
+
[3]:https://github.com/dominikbraun/timetrace
|
|
405
|
+
[4]:https://github.com/samg/timetrap
|
|
406
|
+
[5]:https://github.com/gothenburgbitfactory/timewarrior
|
|
407
|
+
[6]:https://github.com/DylanDevelops/tmpo
|
|
408
|
+
[7]:https://github.com/jazzband/Watson
|
|
409
|
+
[8]:https://github.com/mrusme/zeit
|
|
@@ -4,9 +4,16 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "dey"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.2"
|
|
8
8
|
description = "Terminal time tracker"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
authors = [
|
|
11
|
+
{ name = "David Woodburn", email = "david.woodburn@icloud.com" },
|
|
12
|
+
]
|
|
13
|
+
license = "MIT"
|
|
9
14
|
requires-python = ">=3.7"
|
|
15
|
+
dependencies = [
|
|
16
|
+
]
|
|
10
17
|
|
|
11
18
|
[project.scripts]
|
|
12
19
|
dey = "dey.cli:main"
|
dey-0.2.0/PKG-INFO
DELETED
dey-0.2.0/dey.egg-info/PKG-INFO
DELETED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|