StartAndDueDates

This is a variant of the Due Dates script that also handles start dates, plus some refactoring into functions to make things a bit cleaner.

Feel free to use and modify as you wish. With thanks to the original creator of the script.


   property dueTag : "due"
   property startTag : "start"
   property repeatTag : "repeat"
   property todayTag : "today"
   property pastDueTag : "overdue"
   property upcomingTag : "upcoming"
   property doneTag : "done"
   property inProgressTag : "inprogress"
   property errorTag : "error"
   property removeTags : {upcomingTag, todayTag, pastDueTag, inProgressTag}
   property upcomingDays : 2

property numberSet : {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"}

global vToday set vToday to current date set time of vToday to 0

--Start by converting any due tags with a text description of the date
--to an actual date
my convertDate(dueTag) my convertDate(startTag)

tell front document of application "TaskPaper"

--Next handle repeat tags. A due tag is not required on these.
repeat with tpRptTag in (every tag of (every entry) whose name is repeatTag)
    tell entry of tpRptTag
        set tagList to (every tag whose name is dueTag)
        set needDue to false
        if tagList is {} then
            --no due tag, create one, and remember to fill in a date below.
            --use today as the start date
            set tpDueTag to make new tag with properties {name:dueTag}
            copy vToday to vDate
            set needDue to true
        else
            --have a due tag, use that as the start date
            set tpDueTag to first item of tagList
            set dateString to (get value of tpDueTag)
            tell me to set vDate to getDateFromText(dateString)
        end if
        if not needDue then
            set tagList to (every tag whose name is doneTag)
        end if
        --if there was no due tag, or the entry is marked done,
        --the calculate and set the date of the due tag.
        if needDue or tagList is not {} then
            --Delete all extra tags
            repeat with delTag in removeTags
                delete (every tag whose name is delTag)
            end repeat

            --Create a date from the repeat value
            set rInfo to (get value of tpRptTag)
            if (vDate is not null) then
                tell me to set vDate to getRepeatDate(rInfo, vDate)
            end if

            if vDate is not null then
                --fill in the date, make sure it is not marked done
                tell me to set vDateText to getTextFromDate(vDate)
                set value of tpDueTag to vDateText
                delete (every tag whose name is doneTag)
            else
                --flag unknown repeat value with an error tag
                make new tag with properties {name:errorTag, value:"unknown repeat type"}
            end if
        end if
    end tell
end repeat

--Add/update the extra tags based on the due date of items that are not done
repeat with tpDueTag in (every tag of (every entry) whose name is dueTag)
    tell entry of tpDueTag
        set tagList to (every tag whose name is doneTag)
        set errTagList to (every tag whose name is errorTag)
        if (tagList is {}) and (errTagList is {}) then
            --Not marked done
            set inFuture to false
            set dateString to (get value of tpDueTag)
            tell me to set vDate to getDateFromText(dateString)
            set startTagList to (every tag whose name is startTag)
            if (startTagList is not {}) then
                set tpStartTag to first item of startTagList
                set startDateString to (get value of tpStartTag)
                tell me to set vStartDate to getDateFromText(startDateString)
                set inFuture to ((vToday) - vStartDate < 0)
            end if
            if vDate is not null then
                if inFuture then
                    delete (every tag whose name is upcomingTag)
                    delete (every tag whose name is todayTag)
                else
                    set diffDays to (vDate - vToday) / days
                    if (diffDays < 0) then
                        set tagList to (every tag whose name is pastDueTag)
                        if (tagList is {}) then
                            make new tag with properties {name:pastDueTag}
                        end if
                        delete (every tag whose name is upcomingTag)
                        delete (every tag whose name is todayTag)
                    else if (diffDays = 0) then
                        set tagList to (every tag whose name is todayTag)
                        if (tagList is {}) then
                            make new tag with properties {name:todayTag}
                        end if
                        delete (every tag whose name is upcomingTag)
                    else if (diffDays ≤ upcomingDays) then
                        set tagList to (every tag whose name is upcomingTag)
                        if (tagList is {}) then
                            make new tag with properties {name:upcomingTag}
                            delete (every tag whose name is todayTag)
                        end if
                    else
                        delete (every tag whose name is upcomingTag)
                        delete (every tag whose name is todayTag)
                    end if
                end if
            else
                --invalid date format
                make new tag with properties {name:"error", value:"invalid date format"}
            end if
        else
            --Marked done, delete all extra tags
            repeat with delTag in removeTags
                delete (every tag whose name is delTag)
            end repeat
        end if
    end tell
end repeat

end tell

on convertDate(tagLabel) tell front document of application "TaskPaper" repeat with myTag in (every tag of (every entry) whose name is tagLabel) set vDueVal to (value of myTag) if vDueVal is missing value then set vDueVal to "today" end if if character 1 of vDueVal is not in numberSet then set vDateString to null tell me to set vDate to getDateForDueValue(vDueVal) if vDate is not null then tell me to set vDateString to getTextFromDate(vDate) else tell entry of myTag make new tag with properties {name:errorTag, value:"Unknown value for " & tagLabel & " tag"} end tell end if if vDateString is not null then set value of myTag to vDateString end if end if end repeat end tell end convertDate

on getDateFromText(dateText) set vDate to null set AppleScript's text item delimiters to {"-"} if (count of text item of dateText) is 3 then set vYear to text item 1 of dateText set vMonth to text item 2 of dateText set vDay to text item 3 of dateText if (vYear > 1000) and (vMonth > 0 and vMonth < 13) and (vDay > 0 and vDay < 32) then set vDate to current date set year of vDate to (vYear as integer) set month of vDate to vMonth as integer set day of vDate to vDay as integer set time of vDate to 0 end if end if return vDate end getDateFromText

on getTextFromDate(vDate) set dText to ((year of vDate) as text) & "-" set dayText to (month of vDate as number) as text if length of dayText is 1 then set dayText to "0" & dayText end if set dText to dText & dayText & "-" set dayText to (day of vDate as number) as text if length of dayText is 1 then set dayText to "0" & dayText end if return dText & dayText end getTextFromDate

on getDateForDueValue(dueValue) set vDate to null if character 1 of dueValue is in numberSet then set vDate to getDateFromText(dueValue) else --Special cases for due date not handled in getRepeatDate if "today" is dueValue then copy vToday to vDate else if "tomorrow" starts with dueValue then copy vToday to vDate set vDate to vDate + 1 * days else set vDate to getRepeatDate(dueValue, vToday) end if end if return vDate end getDateForDueValue

on getRepeatDate(repeatDesc, fromDate) copy fromDate to vDate

set AppleScript's text item delimiters to {":"}
set repeatType to text item 1 of repeatDesc
if (count of text items in repeatDesc) > 1 then
    set repeatCount to text item 2 of repeatDesc
else
    set repeatCount to 1
end if

if repeatType is "day" or repeatType is "week" then
    if repeatType is "day" then
        set vInterval to days
    else
        set vInterval to weeks
    end if
    set vDate to vDate + repeatCount * vInterval
    repeat while vDate comes before vToday
        set vDate to vDate + repeatCount * vInterval
    end repeat
else if repeatType is "month" then
    set month of vDate to (month of vDate) + repeatCount
    repeat while vDate comes before vToday
        set month of vDate to (month of vDate) + repeatCount
    end repeat
else if repeatType is "year" then
    set year of vDate to (year of vDate) + repeatCount
    log "vDate is " & vDate
    repeat while vDate comes before vToday
        set year of vDate to (year of vDate) + repeatCount
    end repeat
else
    set rDay to 0
    if "sunday" starts with repeatType then
        set rDay to Sunday
    else if "monday" starts with repeatType then
        set rDay to Monday
    else if "tuesday" starts with repeatType then
        set rDay to Tuesday
    else if "wednesday" starts with repeatType then
        set rDay to Wednesday
    else if "thursday" starts with repeatType then
        set rDay to Thursday
    else if "friday" starts with repeatType then
        set rDay to Friday
    else if "saturday" starts with repeatType then
        set rDay to Saturday
    end if
    if rDay > 0 then
        --Handle case where vDate is not currect day of week.
        set vOffset to rDay - (weekday of vDate)
        if vOffset is not 0 then
            set vDate to vDate + vOffset * days
            if vOffset > 0 then
                --If we move forward, count that as 1
                set repeatCount to repeatCount - 1
            end if
        end if

        --Find next date after vDate
        set vOffset to 7 * repeatCount
        set vDate to vDate + vOffset * days
        repeat while vDate comes before vToday
            set vDate to vDate + vOffset * days
        end repeat
    else
        --Unknown type, return nothing
        set vDate to null
    end if
end if

return vDate

end getRepeatDate

Download Parse Start and Due Dates.applescript

I have modified the above script so that @start tags are removed once the start date is attained. Insert the lines below before the last end tell before on convertDate(tagLabel) [Scalpa].

-- remove start tags if starting today
tell me to set vTodayString to getTextFromDate(vToday)
repeat with currentTag in (every tag of (every entry) whose name is startTag)
    tell entry of currentTag
        set dateString to (get value of currentTag)
        if (dateString is vTodayString) then
            delete (every tag whose name is startTag)
        end if
    end tell
end repeat