repeating google tasks (and more!)

I've put together a script to juice some more mileage out of Google Tasks. This script uses the Google Tasks API to do two things:

  • Create Recurring or Repeating Google Tasks
  • Log all completed Google Tasks to a spreadsheet

I wanted to keep track of (and improve upon) a couple of basic health-related habits this year, so that’s what I do with this thing.

I’ve got a to-do list that reminds me to run and meditate every two days, staggered with floor exercises (and sweeping the floor) on alternate days. It reminds me to mop (or swiff) once a week. Here it is as seen from my android phone:

Google Tasks on Android

Every time I complete a task, it gets logged in a google spreadsheet.

Google Spreadsheet

There’s even a pivot chart to track trends and whatnot.

It’s been pretty smooth and swell for me so far. I’m including the code down below.

Try it out.

Here is a Google Spreadsheet all set to go with the correct headers and even a handy pivot table to help with tracking and analysis. You should be able to save your own copy of the sheet and work from there.

To set up your spreadsheet, you’ll have to enable the Google Tasks API.

From your base Spreadsheet page, go to Tools > Script Editor, and from the Script Editor, go to Resources > Advanced Google Services.

A popup displays a list of APIs. Find ‘Tasks API’ and turn it on.

Follow the link to the Google Developers Console, where you will once again have to find the ‘Tasks API’ entry and turn it on. I’m not sure why you have to do it in two places, but that’s the way of things.

Now For the Code

In the Script Editor tab (the one that opened from your spreadsheet earlier–if you’ve closed it, get back to your spreadsheet and go to Tools > Script Editor.

You may need to create a new blank script. Use the following code.

function pull() { // set spreadsheet var ss = SpreadsheetApp.getActiveSpreadsheet(); var sheet = ss.getSheetByName("THE NAME OF YOUR SHEET GOES HERE"); // select TASKS app task list by title var title = "THE NAME OF YOUR TASK LIST GOES HERE"; var allLists = Tasks.Tasklists.list().getItems(); var id; for (var i in allLists) { if (title == allLists[i].getTitle()) { id = allLists[i].getId(); } } if (!id) { Logger.log("Tasklist not found"); } else { Logger.log("Tasklist found"); } // pull tasks from TASKS app var list = Tasks.Tasks.list(id); var tasks = list.getItems(); // create array of all tasks with desired elements var taskarray = []; for (i = 0; i < tasks.length; i++) { line = []; line.push(tasks[i].getTitle()); line.push(tasks[i].getStatus()); dd = tasks[i].getDue(); // if task has a duedate, strip time data from date // and remove timezone change effects - google doesn't // support due times, due date is at midnight utc if (dd != null) { due = new Date(dd); due.setHours(0); due.setMinutes(0); var dueday = due.getDate(); due.setDate(dueday +1); line.push(due); // if task has no duedate, pass an empty string // into the duedate column } else { line.push(""); } // get timestamp of task completion, separate // time and date, send to separate fields fulldate = (new Date(tasks[i].getCompleted())); date = fulldate.getDate(); month = fulldate.getMonth()+1; year = fulldate.getFullYear(); hours = fulldate.getHours(); minutes = fulldate.getMinutes(); line.push(year + "-" +month+"-"+date); line.push(hours + ":" + minutes); var notes = tasks[i].getNotes(); if (notes != null) { line.push(notes); } else { line.push(""); } // early or late? var oneDay = 24*60*60*1000; var late = Math.round((fulldate.getTime() - due.getTime())/(oneDay)); line.push(late) taskarray.push(line); } // parse task list for completed tasks var done = taskarray.filter(function(value,index){ return value[1]=="completed"; }); for (i = 0; i < done.length; i++); // log completed tasks and notes to spreadsheet - make sure range // (from A:F here) is equal to number of elements in taskarray // (and therefore of done, which is a subset of taskarray) var lr = sheet.getLastRow(); if (i>0) { sheet.getRange("A"+(lr+1)+":G"+(lr+i)).setValues(done); } // clear completed tasks from TASKS app Tasks.Tasks.clear(id); // loop through completed tasks and return them back to TASKS for (var i=0;i")>=0) { duedate = (new Date()); duedate.setHours(0,0,0,0); duedate.setDate(duedate.getDate()+7); duedate = (new Date(duedate).toISOString()); newTask = Tasks.newTask() .setTitle(done[i]) .setDue(duedate) .setNotes(""); var inserted = Tasks.Tasks.insert(newTask, id) } else if (comment.indexOf("")>=0) { var today = new Date(); var currentyear = today.getFullYear(); var currentmonth = today.getMonth(); var currentdate = today.getDate(); if (currentdate>28) { var duedate = new Date(currentyear, currentmonth +2, 0, 0); } else { var duedate = new Date(currentyear, currentmonth +1, currentdate, 0); } var duedatestring = (new Date(duedate).toISOString()); newTask = Tasks.newTask() .setTitle(done[i]) .setDue(duedatestring) .setNotes(""); var inserted = Tasks.Tasks.insert(newTask, id) } else if (>=0) { var repeatnum = comment.match(//); var num = parseFloat(repeatnum[0].match(/\d+/)); duedate = (new Date()); duedate.setHours(0,0,0,0); duedate.setDate(duedate.getDate()+num); duedate = (new Date(duedate).toISOString()); newTask = Tasks.newTask() .setTitle(done[i]) .setDue(duedate) .setNotes(""); var inserted = Tasks.Tasks.insert(newTask, id) } else if (>=0) { newTask = Tasks.newTask() .setTitle(done[i]) .setNotes(""); var inserted = Tasks.Tasks.insert(newTask, id); } } }

Now a simple modification, to make the script reference your chosen task list and spreadsheet:

There’s two variables to set, both of them right at the top of the script:

  • the name of the Sheet in your spreadsheet file (var sheet = ss.getSheetByName(“THE NAME OF YOUR SHEET GOES HERE”);)
  • the name of your task list in Google Tasks (var title = “THE NAME OF YOUR TASK LIST GOES HERE”;)

If you’re using the template I linked to above, you can use the sheet name “tasklog.” For the task list, use whatever list you’d like. My default is “jerome’s tasks” but I chose to instead use a separate list called “repeater.”

Once you set those up, set a trigger. In the script editor, there is an icon of a clock. It gives a tooltip “current project’s triggers.” Click on that. I’ve got mine set to run every five minutes. Once every couple of weeks I get a “volume warning” from the Google Tasks service for posting to many requests. So you might not want to run it any more frequently than that.

Every time it runs, it polls the Google Tasks service and checks your defined list for completed tasks. It logs any completed tasks to your spreadsheet and clears them from the Google Tasks app.

So when you mark a task as complete in Tasks, don’t clear it away. The script will handle that for you.

If any tasks contain a repeat tag in the description, the script sends them back to tasks.

supported description tags new task’s new due date
<!-- repeats --> no due date
<!-- every X day(s) --> due date X days from completion
<!-- weekly --> due date 7 days from completion
<!-- monthly --> due date 1 month from completion

Also, check out the code on github. It’s easier to look at over there, and if you have any ideas about how to make this script better, let me know.

Post a Comment
Newer Post Older Post Home