#!/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()