100 lines
3.1 KiB
Python
100 lines
3.1 KiB
Python
#!/usr/bin/env python3
|
|
"""Am I free to leave the Long Day Factory yet?
|
|
|
|
Time served = (now - startTime) - lunchBreak
|
|
You are free once time served reaches 4 hours.
|
|
|
|
Exit codes:
|
|
0 calculation done (see FREE / NOT FREE in output)
|
|
2 lunch times missing and no decision flag passed -> ask the user
|
|
3 startTime missing -> user must run long-day-start
|
|
"""
|
|
import json
|
|
import sys
|
|
from datetime import datetime, timedelta, time
|
|
from pathlib import Path
|
|
|
|
SENTENCE = timedelta(hours=4)
|
|
DEFAULT_LUNCH_OUT = time(11, 30)
|
|
DEFAULT_LUNCH_IN = time(12, 30)
|
|
F = Path.home() / "long-day-factory.json"
|
|
|
|
|
|
def parse(ts):
|
|
return datetime.fromisoformat(ts) if ts else None
|
|
|
|
|
|
def fmt_delta(td):
|
|
secs = int(td.total_seconds())
|
|
sign = "-" if secs < 0 else ""
|
|
secs = abs(secs)
|
|
h, m = secs // 3600, (secs % 3600) // 60
|
|
return f"{sign}{h}h{m:02d}m"
|
|
|
|
|
|
def main():
|
|
flag = sys.argv[1] if len(sys.argv) > 1 else ""
|
|
|
|
if not F.exists():
|
|
print("No ~/long-day-factory.json found. Run long-day-start first.")
|
|
sys.exit(3)
|
|
|
|
data = json.loads(F.read_text())
|
|
start = parse(data.get("startTime"))
|
|
lunch_out = parse(data.get("lunchTime"))
|
|
lunch_in = parse(data.get("backToWork"))
|
|
|
|
if start is None:
|
|
print("startTime is not set. Run long-day-start first.")
|
|
sys.exit(3)
|
|
|
|
now = datetime.now(start.tzinfo)
|
|
|
|
# Resolve the lunch break.
|
|
note = ""
|
|
if lunch_out and lunch_in:
|
|
lunch_break = lunch_in - lunch_out
|
|
if lunch_break.total_seconds() < 0:
|
|
lunch_break = timedelta(0)
|
|
note = "(backToWork is before lunchTime — treating lunch as 0)"
|
|
elif flag == "--default-lunch":
|
|
d = start.date()
|
|
lunch_out = datetime.combine(d, DEFAULT_LUNCH_OUT, tzinfo=start.tzinfo)
|
|
lunch_in = datetime.combine(d, DEFAULT_LUNCH_IN, tzinfo=start.tzinfo)
|
|
data["lunchTime"] = lunch_out.isoformat()
|
|
data["backToWork"] = lunch_in.isoformat()
|
|
F.write_text(json.dumps(data, indent=2) + "\n")
|
|
lunch_break = lunch_in - lunch_out
|
|
note = "(assumed the standard 11:30-12:30 lunch and saved it)"
|
|
elif flag == "--flat-hour":
|
|
lunch_break = timedelta(hours=1)
|
|
note = "(assumed a flat 1h lunch, not saved)"
|
|
else:
|
|
missing = []
|
|
if not lunch_out:
|
|
missing.append("lunchTime")
|
|
if not lunch_in:
|
|
missing.append("backToWork")
|
|
print("NEEDS_LUNCH_DECISION: missing " + ", ".join(missing))
|
|
sys.exit(2)
|
|
|
|
served = (now - start) - lunch_break
|
|
remaining = SENTENCE - served
|
|
|
|
print(f"Clocked in: {start.isoformat()}")
|
|
print(f"Lunch break: {fmt_delta(lunch_break)} {note}".rstrip())
|
|
print(f"Time served: {fmt_delta(served)}")
|
|
|
|
if remaining.total_seconds() <= 0:
|
|
print("Status: FREE")
|
|
print(f"Overtime: {fmt_delta(-remaining)}")
|
|
else:
|
|
eta = now + remaining
|
|
print("Status: NOT FREE")
|
|
print(f"Remaining: {fmt_delta(remaining)}")
|
|
print(f"Parole at: {eta.strftime('%H:%M')}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|