Skip to content

Commit 88cdc87

Browse files
Add an option to start the timer 1 second after the last time unit
1 parent bcbc242 commit 88cdc87

File tree

2 files changed

+55
-6
lines changed

2 files changed

+55
-6
lines changed

timetracker/cmd/start.py

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
__copyright__ = 'Copyright (C) 2025-present, DV Klopfenstein, PhD. All rights reserved.'
44
__author__ = "DV Klopfenstein, PhD"
55

6+
import os.path as op
7+
from timetracker.csvfile import CsvFile
68
from timetracker.epoch.epoch import get_dt_at
79
from timetracker.cmd import common
810

@@ -13,7 +15,8 @@ def cli_run_start(fnamecfg, args):
1315
fnamecfg,
1416
args.name,
1517
start_at=args.at,
16-
force=args.force)
18+
force=args.force,
19+
uname=args.name)
1720

1821
def _run_start(fnamecfg, name=None, start_at=None, **kwargs):
1922
"""Initialize timetracking on a project"""
@@ -36,8 +39,13 @@ def run_start(cfgproj, name=None, start_at=None, **kwargs):
3639
common.prt_elapsed(startobj)
3740

3841
# Set (if not started) or reset (if start is forced) starting time
39-
if not startobj.started() or force:
40-
starttime = get_dt_at(start_at, kwargs.get('now'), kwargs.get('defaultdt'))
42+
if not startobj.started() or force or start_at == 'last':
43+
starttime = _get_starttime(start_at, cfgproj, kwargs)
44+
# .get('now'),
45+
# kwargs.get('defaultdt'),
46+
# kwargs.get('dirhome'),
47+
# kwargs.get(')
48+
print(f'STARTTIME: {starttime}')
4149
if starttime is None:
4250
return startobj
4351
startobj.wr_starttime(starttime, kwargs.get('activity'), kwargs.get('tag'))
@@ -53,6 +61,17 @@ def run_start(cfgproj, name=None, start_at=None, **kwargs):
5361
print(f'Run `trk start --at {start_at} --force` to force restart')
5462
return startobj
5563

64+
65+
def _get_starttime(start_at, cfgproj, kwargs):
66+
if start_at != 'last':
67+
return get_dt_at(start_at, kwargs.get('now'), kwargs.get('defaultdt'))
68+
fcsv = cfgproj.get_filename_csv(kwargs.get('uname'), kwargs.get('dirhome'))
69+
if op.exists(fcsv):
70+
csvfile = CsvFile(fcsv)
71+
next_startdatetime = csvfile.get_next_start_datetime()
72+
return next_startdatetime if next_startdatetime else None
73+
return get_dt_at(None, kwargs.get('now'), kwargs.get('defaultdt'))
74+
5675
def _get_msg(start_at, force):
5776
if force:
5877
return "start reset to"

timetracker/csvfile.py

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@
44
__copyright__ = 'Copyright (C) 2025-present, DV Klopfenstein, PhD. All rights reserved.'
55
__author__ = "DV Klopfenstein, PhD"
66

7+
import os
78
from os.path import exists
89
from collections import namedtuple
910
from datetime import timedelta
1011
# https://docs.python.org/3/library/csv.html
11-
from csv import writer
12+
import csv
1213

1314
from timetracker.csvutils import get_hdr_itr
1415
from timetracker.epoch.calc import dt_from_str
@@ -47,6 +48,7 @@ def wr_csvline(self, dta, delta, csvfields):
4748
with open(self.fcsv, 'w', encoding='utf8') as csvfile:
4849
self.wr_hdrs(csvfile)
4950
# Print time information into csv
51+
_writer = csv.writer
5052
with open(self.fcsv, 'a', encoding='utf8') as csvfile:
5153
# timedelta(days=0, seconds=0, microseconds=0,
5254
# milliseconds=0, minutes=0, hours=0, weeks=0)
@@ -55,20 +57,25 @@ def wr_csvline(self, dta, delta, csvfields):
5557
data = [str(dta),
5658
str(delta),
5759
csvfields.activity, csvfields.message, csvfields.tags]
58-
writer(csvfile, lineterminator='\n').writerow(data)
60+
_writer(csvfile, lineterminator='\n').writerow(data)
5961
return data
6062
return None
6163

6264
def wr_hdrs(self, prt):
6365
"""Write header"""
6466
print(','.join(self.hdrs), file=prt)
6567

68+
def get_next_start_datetime(self):
69+
"""Get the next start_datetime after the last line in a timetracker csv file"""
70+
ntd = self._rd_last_line()
71+
return ntd.start_datetime + ntd.duration + timedelta(seconds=1) if ntd else None
72+
6673
# ------------------------------------------------------------------
6774
def _get_ntdata(self, csvlines):
6875
"""Get data where start and stop are datetimes; timdelta is calculated from them"""
6976
nto = self.nto
7077
def _get_nt(row):
71-
assert len(row) == 5, f'{self.fcsv} ROW[{len(row)}]: {row}'
78+
assert len(row) == 5, row
7279
return nto(
7380
start_datetime=dt_from_str(row[0]),
7481
duration=td_from_str(row[1]),
@@ -103,5 +110,28 @@ def _read_csv(self, fnc_csvlines):
103110
return self.ntrdcsv(results=fnc_csvlines(itr), error=error)
104111
return self.ntrdcsv(results=None, error=error)
105112

113+
def _rd_last_line(self):
114+
"""Return the last line in the csv file"""
115+
try:
116+
fptr = open(self.fcsv, mode='rb') #encoding='utf8')
117+
except (PermissionError, OSError) as err:
118+
print(type(err).__name__, err.args)
119+
else:
120+
with fptr as csvstrm:
121+
try:
122+
csvstrm.seek(-2, os.SEEK_END)
123+
while csvstrm.read(1) != b'\n':
124+
csvstrm.seek(-2, os.SEEK_CUR)
125+
except OSError:
126+
csvstrm.seek(0)
127+
csv_line = csvstrm.readline().decode()
128+
csv_reader = csv.reader([csv_line])
129+
row = next(csv_reader)
130+
nts = self._get_ntdata([row])
131+
if nts:
132+
assert len(nts) == 1, nts
133+
return nts[0]
134+
return None
135+
106136

107137
# Copyright (C) 2025-present, DV Klopfenstein, PhD. All rights reserved.

0 commit comments

Comments
 (0)