Automating my daily updating of Defer Dates and Times

I have a handful of tasks that repeat every day, some of which repeat more than once a day, e.g.
Write Journal Entry, @mac, Defer 12am
Swap laundry, @home, Defer 7am repeating every 90mins
Take kids to school, @home, 8am
Take medication, @home, 9am

At the end of each day, or the beginning of the next one, if I don’t complete them, I manually move each one forward to the next day at its “default” start time. So for instance, I’d add 1 day to Write Journal Entry but if I’d swapped the laundry twice or three times, I’d manually change “Today, 10am” to the next day 7am.

Dan Bylar’s scripts get me MOST of the way there, but don’t work for the time element.

Is there a way I can automate this process, so that I tell OmniFocus “Here are my defaults for these x number of tasks. Please set them at the right times today, even they’re ‘wrong’ right now.”?

Thanks, Andrew

1 Like

Hey Andrew,

I haven’t seen Dan’s script, but I’m wondering if this omni-automation script would work for you.

You add a tag (currently set to “auto-defer”) to indicate what tasks you want it to consider and you include a default time in the note (ie. “Default Time: 7:00AM”) to indicate the time you want it to reset to. You run it from the “Automation” menu.

Let me know if something could improve this or if you have any questions.




Summary

This text will be hidden

CODE

// COPY & PASTE into editor app. EDIT & SAVE with “.omnifocusjs” file extension.
/*{
    "type": "action",
    "targets": ["omnifocus"],
    "author": "Matthew Johnson",
    "identifier": "com.matthewjohnson",
    "version": "1.0",
    "description": "Defers tasks in the past if they have the tag 'auto-defer' and a default defer time in the notes (ie. 'Default Time: 07:00:00AM)",
    "label": "Auto-Defer Tasks",
    "shortLabel": "Auto-Defer Tasks",
    "paletteLabel": "Auto-Defer Tasks",
    "image": "clock.arrow.circlepath"
}*/
(() => {
    const action = new PlugIn.Action(async function (selection, sender) {
        try {
            // selection options: tasks, projects, folders, tags, databaseObjects, allObjects
            var tagName = 'auto-defer'                  // [ CAN UPDATE ] {String} This is the tag that marks tasks for auto-deferment
            var defaultTimeString = 'Default Time: ';   // [ CAN UPDATE ] {String}
            var onlyNextDay = false;                    // [ CAN UPDATE ] {Boolean} Should tasks be defered to the next day if the day is not over?


            var d = new Date(); (onlyNextDay ? d.setHours(0) : '');
            var tgs = flattenedTags;
            var toDefer = flattenedTags.byName(tagName).tasks.filter(task => task.deferDate < d);

            var updatedTasks = toDefer.map((task) => {
                var note = task.note;
                var stringStart = note.indexOf(defaultTimeString) + defaultTimeString.length;
                var stringEnd = note.indexOf("\n", stringStart);
                var defaultTime = note.substring(stringStart, (stringEnd > 0 ? stringEnd : note.length));
                // (?<=Default Time: )(.*)
                // var defaulTime = note.match(/(?<=\defaultTimeString)(.*)

                var hms = defaultTime.replace(' ', '').split(':');
                var h = hms[0].substring(hms[0].length - 2, hms[0].length);
                var m = hms[1].substring(0, 2);
                var s = hms.length > 2 ? hms[2].substring(0, 2) : '00';
                defaultTime.toLowerCase().includes('pm') ? h += 12 : '';
                defaultTime.toLowerCase().includes('am') && h == 12 ? h = '00' : '';
                h.length == 1 ? h = '0' + h : '';
                m.length == 1 ? m = '0' + m : '';
                var hms = `${h}:${m}:${s}`;


                var deferDate = task.deferDate;
                var deferDateDateTime = deferDate.toISOString();
                var deferDateDate = deferDateDateTime.split('T')[0];
                var target = new Date(deferDateDate + 'T' + hms);
                target.setDate(target.getDate() + 1);

                task.deferDate = target;

                var results = { 'Task Name': task.name, 'Old Date': deferDate, 'New Date': task.deferDate };
                return results;
            });
        }
        catch (err) {
            if (!err.causedByUserCancelling) {
                console.error(err.name, err.message)
                //new Alert(err.name, err.message).show()
            }
        }
    });

    action.validate = function (selection, sender) {
        // selection options: tasks, projects, folders, tags, databaseObjects, allObjects
        return true
    };

    return action;
})();

of-autoDeferTasks.omnijs (3.2 KB)

Matt, That’s INCREDIBLE. What an elegant solution. Thank you SO much!

Hi Matt,

Not to look a TREMENDOUS gift horse in the mouth, is there any way to add an unusual character to the title of the Task, e.g.

Write Journal entry ©

and use that as a filter for the Automation, rather than a Tag?

Thanks, Andrew

@asaffer, that’s a great idea!

I’ve updated it so tasks can be marked with a tag and/or a special character/string in the name. If desired, it is also possible to search the note for the same special character as the name.

// COPY & PASTE into editor app. EDIT & SAVE with “.omnifocusjs” file extension.
/*{
    "type": "action",
    "targets": ["omnifocus"],
    "author": "Matthew Johnson",
    "identifier": "com.matthewjohnson",
    "version": "1.0",
    "description": "Defers tasks in the past if they have the tag 'auto-defer' and a default defer time in the notes (ie. 'Default Time: 07:00:00AM)",
    "label": "Auto-Defer Tasks",
    "shortLabel": "Auto-Defer Tasks",
    "paletteLabel": "Auto-Defer Tasks",
    "image": "clock.arrow.circlepath"
}*/
(() => {
    const action = new PlugIn.Action(async function (selection, sender) {
        try {
            // selection options: tasks, projects, folders, tags, databaseObjects, allObjects

            // tasks can be marked with a tag and/or a special character/string in the name. If desired, it is also possible to search the note for the same special character as the name.

            var searchTag = true;                       // [ CAN UPDATE ] {Boolean} Search for tag
            var searchName = true;                      // [ CAN UPDATE ] {Boolean} Search the task name
            var searchNote = false;                     // [ CAN UPDATE ] {Boolean} Search the task note
            var tagName = 'auto-defer';                 // [ CAN UPDATE ] {String} This is the tag that marks tasks for auto-deferment
            var specialCharacter = '©';                 // [ CAN UPDATE ] {String} This is the string in the task name that marks tasks for auto-deferment
            var defaultTimeString = 'Default Time: ';   // [ CAN UPDATE ] {String}
            var onlyNextDay = false;                     // [ CAN UPDATE ] {Boolean} Should tasks be defered to the next day only if the day is over?
            var catchUpOldTasks = true;                 // [ CAN UPDATE ] {Boolean} Should old tasks be caught up to present day (true) or bumped up one day at a time (false)?


            var d = new Date(); (onlyNextDay ? d.setHours(0) : '');
            var taskIds = new Array();
            var toDefer = new Array();
            var tgs = flattenedTags;
            var tsks = flattenedTasks;
            var bySpecialChar_inName = new Array();
            var byString_inTag = new Array();
            var bySpecialChar_inDesc = new Array();
            
            // GET TASKS BASED ON NAME SEARCH
            if (searchName) bySpecialChar_inName = tsks.filter((tsk) => tsk.name.includes(specialCharacter));
            console.log('Name: ' + bySpecialChar_inName);

            // GET TASKS BASED ON TAG SEARCH
            if (searchTag && tagName != '' && tagName != null) byString_inTag = flattenedTags.byName(tagName).tasks.filter(tsk => tsk.deferDate < d);
            console.log('Tag: ' + byString_inTag);

            // GETS TASKS BASED ON NOTE SEARCH
            if (searchNote) bySpecialChar_inDesc = tsks.filter((tsk) => tsk.note.includes(specialCharacter));
            console.log('Desc: ' + bySpecialChar_inDesc);

            // COMBINES SEARCHES
            searchResults = byString_inTag.concat(bySpecialChar_inName, bySpecialChar_inDesc);
            console.log('Search Results: ' + searchResults);
            
            // Removes duplicate, dropped, and completed tasks
            searchResults.forEach((tsk) => {
                if (!taskIds.includes(tsk.id.primaryKey) && tsk.deferDate < d && tsk.active && !tsk.completed) {
                    taskIds.push(tsk.id.primaryKey);
                    toDefer.push(tsk);
                    return tsk;
                }
            })
            console.log('To Defer: ' + toDefer);



            var updatedTasks = toDefer.map((tsk) => {
                var note = tsk.note;
                var stringStart = note.indexOf(defaultTimeString) + defaultTimeString.length;
                var stringEnd = note.indexOf("\n", stringStart);
                var defaultTime = note.substring(stringStart, (stringEnd > 0 ? stringEnd : note.length));
                // (?<=Default Time: )(.*)
                // var defaulTime = note.match(/(?<=\defaultTimeString)(.*)

                var hms = defaultTime.replace(' ', '').split(':');
                var h = hms[0].substring(hms[0].length - 2, hms[0].length);
                var m = hms[1].substring(0, 2);
                var s = hms.length > 2 ? hms[2].substring(0, 2) : '00';
                defaultTime.toLowerCase().includes('pm') ? h += 12 : '';
                defaultTime.toLowerCase().includes('am') && h == 12 ? h = '00' : '';
                h.length == 1 ? h = '0' + h : '';
                m.length == 1 ? m = '0' + m : '';
                var hms = `${h}:${m}:${s}`;

                // var d = new Date()
                // var deferDateDate = d.toLocaleString().split(",")[0]
                // console.log(deferDateDate)
                // var target = new Date(deferDateDate)
                // console.log(target)

                var deferDate = catchUpOldTasks ? d : tsk.deferDate;
                var deferDateDateTime = deferDate.toLocaleString();
                var deferDateDate = deferDateDateTime.split(',')[0];
                var target = new Date(deferDateDate + ' ' + hms);
                target.setDate(target.getDate() + 1);   



                // var deferDateDateTime = deferDate.toISOString();
                // var deferDateDate = deferDateDateTime.split('T')[0];
                // var target = new Date(deferDateDate + 'T' + hms);

                tsk.deferDate = target;

                var results = { 'Task Name': tsk.name, 'Old Date': deferDate, 'New Date': tsk.deferDate };
                return results;
            });
        }
        catch (err) {
            if (!err.causedByUserCancelling) {
                console.error(err.name, err.message)
                //new Alert(err.name, err.message).show()
            }
        }
    });

    action.validate = function (selection, sender) {
        // selection options: tasks, projects, folders, tags, databaseObjects, allObjects
        return true
    };

    return action;
})();

of-autoDeferTasks.omnijs (5.9 KB)

1 Like

Matt, This in UNBELIEVABLE! Thank you SO much, Andrew

Glad to help!

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.