Calculate 4th Thursday of the month in Omnifocus

I love the power and flexibility of Omnifocus but a common problem I’ve been having is to create monthly repeating actions on the fourth Thursday of the month or other dates like that. I couldn’t find a way to do this within Omnifocus, so I made a script to do it for me.

It relies on a wonderful function from macscripter, which calculates the date of the fourth Thursday from any given day and another one which calculates the first of the month. From those I get the fourth Thursday of the month and create a task in Omnifocus. As with my gmail backup, I log the date the script runs, to make sure there are no duplicate tasks. Now I have a repeating macro in Keyboard Maestro, which runs the script and I never again have to spend time worrying about when to move the car for street cleaning. Here’s the script:

property myContext : "Home"
set todaysDate to (current date)
set thetext to todaysDate as string
set theHomePath to (path to home folder) as string
set thefilePath to theHomePath & "Library:ScriptSupport:LastDate_MoveCar.txt" as string
try
set oldDate to date (read (file thefilePath))
on error
set oldDate to (todaysDate - 40 * days)
end try
if month of oldDate is not month of todaysDate then
set newDate1 to (DateOfThisInstanceOfThisWeekdayBeforeOrAfterThisDate(firstOfThisMonth(todaysDate), Thursday, 4) - 1 * days)
set newDate2 to DateOfThisInstanceOfThisWeekdayBeforeOrAfterThisDate(firstOfThisMonth(todaysDate), Thursday, 4)
set newDate3 to (DateOfThisInstanceOfThisWeekdayBeforeOrAfterThisDate(firstOfThisMonth(todaysDate), Friday, 4) - 1 * days)
set newDate4 to DateOfThisInstanceOfThisWeekdayBeforeOrAfterThisDate(firstOfThisMonth(todaysDate), Friday, 4)
tell application "OmniFocus"
tell default document
set theContext to context myContext
make new inbox task with properties {name:"move car to opposite side of house", context:theContext, start date:newDate1, due date:newDate2}
make new inbox task with properties {name:"move car to same side of house", context:theContext, start date:newDate3, due date:newDate4}
compact
end tell
end tell
try
set eof of file thefilePath to 0
write thetext to file thefilePath starting at eof
on error
tell application "Finder"
make new file in (theHomePath & "Library:ScriptSupport") with properties {name:"LastDate_MoveCar.txt"}
end tell
write thetext to file thefilePath starting at eof
end try
end if
on firstOfThisMonth(theDate) -- returns a date
copy theDate to d
set d's day to 1
d -- return the resulting date
end firstOfThisMonth
on DateOfThisInstanceOfThisWeekdayBeforeOrAfterThisDate(d, w, i) -- returns a date
-- Keep an note of whether the instance value *starts* as zero
set instanceIsZero to (i is 0)
-- Increment negative instances to compensate for the following subtraction loop
if i < 0 and d's weekday is not w then set i to i + 1
-- Subtract a day at a time until the required weekday is reached
if d's weekday is w then
d + (i - 1) * weeks - (d's time)
else
repeat until d's weekday is w
set d to d - days
-- Increment an original zero instance to 1 if subtracting from Sunday into Saturday
if instanceIsZero and d's weekday is Saturday then set i to 1
end repeat
-- Add (adjusted instance) * weeks to the date just obtained and zero the time
d + i * weeks - (d's time)
end if
end DateOfThisInstanceOfThisWeekdayBeforeOrAfterThisDate