Consolidating my little date commands
February 7, 2023 at 9:11 AM by Dr. Drang
This morning, I was composing a nice email to a client, and I needed to know how many days it had been since September 23 of last year: This invoice is 137 days old. When the fuck are you going to pay it? I used my ago
script, which worked fine, except I needed to switch from Mail to Terminal to run it. It got me thinking Why the fuck haven’t I turned this into a macro I can call from within any app? Apparently, I had a couple of fucks to give this morning.
After a little thought, I realized that a Keyboard Maestro macro with the right kind of user input prompt could incorporate all of my little date commands and would be faster and easier to use than any of them.
My three little date commands are since
(previously named ago
), til
, and between
. since
takes one argument, a date in the past, and returns the number of days from that date to today. til
also takes one argument, a date in the future, and returns the number of days from today to that date.1 between
takes two date arguments and returns the number of days between them.
My new Keyboard Maestro macro, Days Between, uses the logic of between
, but its interface is set up so I only have to enter one date if I want to use it like since
or til
, which are the commands I use most often.
Here’s how it works. I invoke the Days Between macro with ⌃⌘D to bring up this window.
Days Between needs two dates, but by prefilling both the starting and ending date fields with today’s date, I only have to enter one of those dates if I’m doing a since
or til
calculation. This is a very simple solution to the problem of making a single macro that handles all three cases with the least amount of effort for the user. Why I didn’t think of it years ago is a mystery.
After entering a date, say September 23, 2022, for the start date, and pressing the Return key,2 the input window vanishes and the output appears in a notification window in the upper right corner of the screen.
The notification window disappears after a few seconds.
Sometimes I want to just want to see the answer, sometimes I want the answer on the clipboard so I can paste it somewhere. Hence the Copy Answer to Clipboard checkbox, which I can check quickly via the tab and spacebar keys. At present, the checkbox is unchecked by default; I’ll change that if I find myself checking it most of the time.
This is discussed in my earlier post, but it’s worth a mention here, too. Days Between uses Python’s dateutil
library to parse the input dates. There’s a fair amount of flexibility in dateutil
’s parse
command. It will handle both hyphens and slashes as separators, it can be configured to handle either month-first or day-first dates, it understands (within some limits) two-digit years, and you don’t need to include the year at all if it’s the current year.
Here’s what the Days Between macro looks like. It doesn’t take long to build, but you can also download it.
The Python script that does the calculations is
python:
1: #!/usr/bin/env python3
2:
3: import os
4: from dateutil.parser import parse
5:
6: day1 = parse(os.environ['KMVAR_Local_Start_Day'], dayfirst=False, yearfirst=False)
7: day2 = parse(os.environ['KMVAR_Local_End_Day'], dayfirst=False, yearfirst=False)
8:
9: between = day2 - day1
10: print(f'{abs(between.days)} days')
Since Apple no longer includes Python with macOS, you’ll have to install it yourself through the Xcode Command Line Tools, Homebrew, or some other means. Depending on how you install Python, you may also need to install dateutil
. I’m currently using Python 3.8—any version after that should work. Finally, you may need to fiddle with the shebang line to get Keyboard Maestro to know where Python is installed on your computer. Or, better yet, learn how Keyboard Maestro’s ENV_PATH
variable works.
I guess the moral of the story is to keep thinking about your automations, even those that have been working fine for years. There may be room for improvement.
-
since
andtil
are actually the same program saved under two different names. The name used to call the program determines the sign of the return value.since
returns a postive value if the argument is before today and a negative value if the argument is after today.til
does the opposite. ↩ -
Or clicking the OK button, but I doubt I’ll ever use a mouse or trackpad when interacting with this macro. ↩