Anarcat recently wrote about Qalculate, and I think I’m a convert, even though I’ve only barely scratched the surface.
The thing I almost immediately started using it for is time calculations. When I started tracking my time, I quickly found that Timewarrior was good at keeping all the data I needed, but I often found myself extracting bits of it and reprocessing it in variously clumsy ways. For example, I often don’t finish a task in one sitting; maybe I take breaks, or I switch back and forth between a couple of different tasks. The raw output of timew summary is a bit clumsy for this, as it shows each chunk of time spent as a separate row:
$ timew summary 2025-02-18 Debian Wk Date Day Tags Start End Time Total W8 2025-02-18 Tue CVE-2025-26465, Debian, 9:41:44 10:24:17 0:42:33 next, openssh Debian, FTBFS with GCC-15, 10:24:17 10:27:12 0:02:55 icoutils Debian, FTBFS with GCC-15, 11:50:05 11:57:25 0:07:20 kali Debian, Upgrade to 0.67, 11:58:21 12:12:41 0:14:20 python_holidays Debian, FTBFS with GCC-15, 12:14:15 12:33:19 0:19:04 vigor Debian, FTBFS with GCC-15, 12:39:02 12:39:38 0:00:36 python_setproctitle Debian, Upgrade to 1.3.4, 12:39:39 12:46:05 0:06:26 python_setproctitle Debian, FTBFS with GCC-15, 12:48:28 12:49:42 0:01:14 python_setproctitle Debian, Upgrade to 3.4.1, 12:52:07 13:02:27 0:10:20 1:44:48 python_charset_normalizer 1:44:48
So I wrote this Python program to help me:
#! /usr/bin/python3 """ Summarize timewarrior data, grouped and sorted by time spent. """ import json import subprocess from argparse import ArgumentParser, RawDescriptionHelpFormatter from collections import defaultdict from datetime import datetime, timedelta, timezone from operator import itemgetter from rich import box, print from rich.table import Table parser = ArgumentParser( description=__doc__, formatter_class=RawDescriptionHelpFormatter ) parser.add_argument("-t", "--only-total", default=False, action="store_true") parser.add_argument( "range", nargs="?", default=":today", help="Time range (usually a hint, e.g. :lastweek)", ) parser.add_argument("tag", nargs="*", help="Tags to filter by") args = parser.parse_args() entries: defaultdict[str, timedelta] = defaultdict(timedelta) now = datetime.now(timezone.utc) for entry in json.loads( subprocess.run( ["timew", "export", args.range, *args.tag], check=True, capture_output=True, text=True, ).stdout ): start = datetime.fromisoformat(entry["start"]) if "end" in entry: end = datetime.fromisoformat(entry["end"]) else: end = now entries[", ".join(entry["tags"])] += end - start if not args.only_total: table = Table(box=box.SIMPLE, highlight=True) table.add_column("Tags") table.add_column("Time", justify="right") for tags, time in sorted(entries.items(), key=itemgetter(1), reverse=True): table.add_row(tags, str(time)) print(table) total = sum(entries.values(), start=timedelta()) hours, rest = divmod(total, timedelta(hours=1)) minutes, rest = divmod(rest, timedelta(minutes=1)) seconds = rest.seconds print(f"Total time: {hours:02}:{minutes:02}:{seconds:02}")
$ summarize-time 2025-02-18 Debian Tags Time ─────────────────────────────────────────────────────────────── CVE-2025-26465, Debian, next, openssh 0:42:33 Debian, FTBFS with GCC-15, vigor 0:19:04 Debian, Upgrade to 0.67, python_holidays 0:14:20 Debian, Upgrade to 3.4.1, python_charset_normalizer 0:10:20 Debian, FTBFS with GCC-15, kali 0:07:20 Debian, Upgrade to 1.3.4, python_setproctitle 0:06:26 Debian, FTBFS with GCC-15, icoutils 0:02:55 Debian, FTBFS with GCC-15, python_setproctitle 0:01:50 Total time: 01:44:48
Much nicer. But that only helps with some of my reporting. At the end of a month, I have to work out how much time to bill Freexian for and fill out a timesheet, and for various reasons those queries don’t correspond to single timew tags: they sometimes correspond to the sum of all time spent on multiple tags, or to the time spent on one tag minus the time spent on another tag, or similar. As a result I quite often have to do basic arithmetic on time intervals; but that’s surprisingly annoying! I didn’t previously have good tools for that, and was reduced to doing things like str(timedelta(hours=..., minutes=..., seconds=...) + ...) in Python, which gets old fast.
Instead:
$ qalc '62:46:30 - 51:02:42 to time' (225990 / 3600) − (183762 / 3600) = 11:43:48
I also often want to work out how much of my time I’ve spent on Debian work this month so far, since Freexian pays me for up to 20% of my work time on Debian; if I’m under that then I might want to prioritize more Debian projects, and if I’m over then I should be prioritizing more Freexian projects as otherwise I’m not going to get paid for that time.
$ summarize-time -t :month Freexian Total time: 69:19:42 $ summarize-time -t :month Debian Total time: 24:05:30 $ qalc '24:05:30 / (24:05:30 + 69:19:42)' (86730 / 3600) / ((86730 / 3600) + (249582 / 3600)) ≈ 0.2578855349
I love it.
from Planet Ubuntu https://ift.tt/ntbsWwg
No comments: