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

    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}
        end tell
    end tell

        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)
        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

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s