rc/bin/work
2020-02-19 12:12:28 -05:00

201 lines
6 KiB
Python
Executable file

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import argparse
from signal import signal, SIGINT
import sys
from time import sleep
from os.path import expanduser, join
from datetime import datetime, timedelta
TIME_FILE = join(expanduser("~"), "timekeeping.csv")
TODAY_FILE = join(expanduser("~"), ".timekeeping")
is_on_break = False
today_fields = []
start_time = datetime.now()
def die(*args):
print("Error: {}".format(*args), file=sys.stderr)
sys.exit(1)
def log(*args):
print(*args, file=sys.stderr)
def signal_handler(signal, frame):
global today_fields
now = datetime.now()
hour = now.strftime("%H:%M")
if not is_on_break:
sys.exit(0)
else:
break_time = now - start_time
log("\nBreak ended at {} and lasted {}".format(
hour, td_format(break_time)))
today_fields.append(start_time.strftime("%H:%M"))
today_fields.append(hour)
with open(TODAY_FILE, "w") as f:
f.write(",".join(today_fields))
sys.exit(0)
def td_format(td):
hours, remainder = divmod(td.total_seconds(), 3600)
minutes, seconds = divmod(remainder, 60)
return '{:d}:{:02d}'.format(int(hours), int(minutes))
def get_today_fields():
try:
with open(TODAY_FILE, "r") as f:
for line in f:
if line.startswith(start_time.strftime("%Y-%m-%d")):
return line.strip().split(",")
except FileNotFoundError:
return []
return []
def work(args):
fields = get_today_fields()
if len(fields) < 2:
die("you haven't started working yet today")
print("stats: {}".format(fields))
def work_start(args):
fields = get_today_fields()
hour = start_time.strftime("%H:%M")
if fields:
die("You already started working")
with open(TODAY_FILE, "w") as f:
f.write("{},{}".format(
start_time.strftime("%Y-%m-%d"), hour))
log("Started working at {}".format(hour))
def work_pause(args):
global is_on_break
global today_fields
is_on_break = True
today_fields = get_today_fields()
hour = start_time.strftime("%H:%M")
if not today_fields:
die("no work to take a break from")
log("Taking a break at {}".format(hour))
# Wait to be stopped by a Ctrl-C
sleep(999999)
def work_end(args):
fields = get_today_fields()
hour = start_time.strftime("%H:%M")
if not fields:
die("Why try to leave when you haven't even started")
fields.append(hour)
# Test for even number of timestamp (but fields[0] is the date)
if len(fields) < 3:
die("not enough fields in {}".format(TODAY_FILE))
elif len(fields) % 2 == 0:
die("odd number of timestamps in {}".format(TODAY_FILE))
begin_time = None
worked_time = timedelta()
for field in fields[1:]:
try:
if begin_time is None:
begin_time = datetime.strptime(field, "%H:%M")
else:
end_time = datetime.strptime(field, "%H:%M")
worked_time += end_time - begin_time
begin_time = None
except ValueError:
die("couldn't parse field '{}' in {}".format(
field, TODAY_FILE))
day_start = datetime.strptime(fields[1], "%H:%M")
day_end = datetime.strptime(fields[-1], "%H:%M")
total_time = day_end - day_start
break_time = total_time - worked_time
with open(TIME_FILE, "a") as f:
f.write("{},{},{},{},{},{}\n".format(
fields[0],
day_start.strftime("%H:%M"),
start_time.strftime("%H:%M"),
td_format(break_time),
td_format(worked_time),
args.description))
# Erase TODAY_FILE
with open(TODAY_FILE, "w") as f:
f.write("")
f.flush()
log("Finished working at {} after working {}".format(
hour, td_format(worked_time)))
def work_export(args):
print("export")
def work_parse(args):
new_lines = []
try:
with open(args.file, "r") as f:
for line in f:
fields = line.split(",")
if len(fields) < 6:
break
morning = datetime.strptime(fields[1], "%H:%M")
break_start = datetime.strptime(fields[2], "%H:%M")
break_end = datetime.strptime(fields[3], "%H:%M")
evening = datetime.strptime(fields[4], "%H:%M")
break_time = break_end - break_start
full_day = evening - morning
work_day = full_day - break_time
new_lines.append('{},{},{},{},{},{}'.format(
fields[0],
morning.strftime("%H:%M"),
evening.strftime("%H:%M"),
td_format(break_time),
td_format(work_day),
"".join(fields[5:]).strip()))
except FileNotFoundError:
die("file not found: {}".format(args.file))
# TODO do sanity checking, like if a day already exists
with open(TIME_FILE, "a") as f:
for line in new_lines:
f.write("{}\n".format(line))
log("Written {} new entries to {}".format(len(new_lines), TIME_FILE))
if __name__ == "__main__":
# Handle Ctrl-C
signal(SIGINT, signal_handler)
parser = argparse.ArgumentParser()
parser.set_defaults(func=work)
commands = parser.add_subparsers(dest="command")
start_parser = commands.add_parser("start")
pause_parser = commands.add_parser("pause")
end_parser = commands.add_parser("end")
export_parser = commands.add_parser("export")
parse_parser = commands.add_parser("parse")
start_parser.set_defaults(func=work_start)
pause_parser.set_defaults(func=work_pause)
end_parser.add_argument("description")
end_parser.set_defaults(func=work_end)
export_parser.set_defaults(func=work_export)
parse_parser.set_defaults(func=work_parse)
parse_parser.add_argument("file")
args = parser.parse_args()
args.func(args)
#now = datetime.now()
#with open(TIME_FILE, "r") as f:
# for line in f:
# print(line.strip())