How to send a task to iCal? (Apple Script)

Couldn’t find anywhere, but I’m sure it has to be possible… right?

To add a script as a service, then right click on the task, Services ▸ Add to Calendar and boooom!

I’m sure there is some genius with a brilliant idea here.

There is no need for an apple script. You can select a task in OmniFocus and drag it onto iCal and it creates an entry. Some details in this great blog post.

For me it doesn’t work, i just tried it.

I am using OS X Yosemite version 10.10.2 with OmniFocus Pro 2.1. I open iCal, select the calendar in iCal I want to create the task on, and then pick a task in OmniFocus and I am able to drag it over to iCal to the time I want to create the event. I tried it with the “Day” as well as the “Week” view in iCal and I had no problems with it. I also tried it with BusyCal and it works there as well for me.

It creates only 1h long events. Doesn’t matter due date, estimated time, or how many tasks are selected. It will be always just 1 hour long task with the copied task name as the even name.

I would see this as an amazing feature, if I could add the Apple Script to the toolbar, one click, and BAZAMI! I have all the tasks created:
• Estimated time says how long is the event and due date/time says when the event starts/ends
• The notes are also copied
• possibly other options added

I have no idea where to start. I’m willing to learn more about scripting, but is that even possible?

It’s entirely possible, it’s just a matter of reading the details from the OF task and mapping those properties to an iCal event. I was going to throw something together to give you a starting point but then I realized that, at least the way my OF database is set up, I’d end up with a dozen tasks either all starting at the same time to ending at the same time. As 99% of my tasks use the default start/end times. Do you set specific start/end times to your tasks?

You could, with a little work, send a group of tasks to iCal with them starting at a given time, allowing for the duration of the task, adding a short break, then moving on to the next task.

What are you trying to accomplish? Scheduling your work for the day based on the tasks due today? Or mapping all your tasks to their respective due dates in iCal?

Edit: typo that was driving me crazy

1 Like

(In OmniFocus)
For some tasks, yes. Generally, no. Not every project or task requires meeting a person, be in a certain place, or performing the task/project during a certain time.
So why to have it in OF and in iCal/BusyCal, right?

Presuming that I could choose which tasks go to iCal/BusyCal I would select only those projects/tasks, which should appear as events in the calendar (projects or tasks that are time and/or location specific).
It supposed to block the time in iCal/BusyCal. Even when the time is not specified/established, the day and the duration are. As of now, neither application provides any automation in the process.

Many users, me including, in order to plan/schedule something, have to switch back and forth between iCal and OF to check tasks/projects in OF, then in iCal availability/possibility to reschedule, etc.

I have 2 displays, even when I work remotely, but it’s still not the solution.

Forecast is not helpful in any way, since it’s not meant to be for scheduling, and there is no scrollable calendar view even in the Forecast perspective.
Calendar Events should be visible in any project/folder/perspective/context. Such a waste.

Please write if you have more questions, or something is not clear.

1 Like

You can absolutely set events in Calendar from Applescript. What you need is the input in some way that can be parsed. One idea that comes to mind after reading this page and this page are that you might be able to use the new Share->Mail feature in the OF toolbar to send an event to Mail.app which could be parsed via a mail rule like on the first page I linked above.

This is more an inspiration post than a how-to. Good luck!

This should get you pointed in the right direction.

Notes and disclaimers: this is quick and dirty, nested tell blocks are generally frowned upon, there’s no error capture; works on tasks only; tasks are added to calendar on their start date at their start time, blank start dates are added to calendar at “now” time; if all the tasks selected are the default start time, it’s going to make a big pile of calendar events at that time; tasks without estimated minutes are given a 15-minute block.

    set today to current date
    set theCal to "Home" as string
    
        tell application "OmniFocus"
        	tell content of first document window of front document
    		set theTasks to value of (selected trees where class of its value is not item and class of its value is not folder)
    		repeat with aTask in theTasks
    			set theAction to name of aTask
    			set theStart to start date of aTask
    			if theStart is missing value then set theStart to today
    			set theDuration to estimated minutes of aTask
    			if theDuration is missing value then set theDuration to "15"
    			set theURI to "omnifocus:///task/" & id of aTask
    			
    			tell application "Calendar"
    				make new event at end of events of calendar theCal with properties {summary:theAction, start date:theStart, end date:theStart + (theDuration * minutes), url:theURI}
    			end tell
    			
    		end repeat
    	end tell
    end tell
1 Like

Have you already tried this at least for due items, OP?

@TheWart
This is not what I really need. It makes only more mess than necessary in iCal, since it shows all the tasks with a due date, and this option disregards any additional information, especially the Estimated Time.

@aeryn
I modified the script a little and it works, but I would want to add something extra.

How do I specify (what command?) if I want to add something to the original name of the task?
For example, an emoji “CALENDAR” or “TEAR-OFF CALENDAR”
I would want it before the name, to indicate that it is already in iCal. Any ideas?

Try something like this. I use it for a script when I add a “Read Book X” project. It asks for the book title and then uses the input later in the script.

repeat
	display dialog "Enter Name of Book" default answer "Text"
	try
		if the text returned of result is not "" then
			set the _bookname to the text returned of the result
			exit repeat
		end if
	on error
		beep
	end try
end repeat
1 Like
    set origName to name of aTask
    set newName to "📅 " & origName
    set name of aTask to newName

Just include that somewhere in the repeat block, after you set “theAction” variable or the calendar event will have the emoji too.

1 Like

Hi there,

thanks @aeryn for this script - it’s (almost) exactly what I was looking for! Is there a way to automatically adjust the starting time? E.g. if I have 5 tasks deferred to the same starting day, they all end up at 9am. What would be awesome is if they could be staggered - the first one at 9am, the next one at 10am, and so on, without me having to give them starting times manually. It would just be easier to read on the calendar (it’s not proper scheduling, that would happen on the day and that’s why this tasks are in a separate calendar).

any help much appreciated!

Do the tasks have a duration? If so, this line
set theDuration to estimated minutes of aTask
should stagger the tasks based on their respective length.

If the tasks don’t have a duration, this line
if theDuration is missing value then set theDuration to "15"
should be staggering them by 15 minutes.

Changing “15” to “60” will stagger the tasks by an hour. If they’re still all piling up at 9am, post your code and I’ll take a look.

Disclaimer: OF has changed some of their AppleScript dictionary in the 4 years since I posted this script. I don’t think any of their changes affect this script but I can’t be sure. (Mainly because it’s very very early in the morning right now) :-)

thanks @aeryn I much appreciate the early morning effort (hope you’ve had some coffee by now…).

I tried it again with three tasks stripped of everything except a defer date, and they all got popped onto 9am, each 60min long. I’ve posted the script below.

The reason why I want them on the calendar in the first place, is so I can pull the calendar events and email them to my work email, where I can then schedule them properly throughout my work day(s), and be alerted to things I should start asap. (I’m using a Siri Shortcut fo this currently, it would be even more awesome if I could automate this with a script that runs at 7am without me having to do anything, so my email with new tasks awaits me at work, but thats a different script I suppose). I"m really really new to scripting, so I am struggling to say the least ( a dictionary? from OmniFocus?) and I appreciate your help!

set today to current date
set theCal to "Omni" as string

tell application "OmniFocus"
	tell content of first document window of front document
		set theTasks to value of (selected trees where class of its value is not item and class of its value is not folder)
		repeat with aTask in theTasks
			set theAction to name of aTask
			set theStart to defer date of aTask
			if theStart is missing value then set theStart to today
			set theDuration to estimated minutes of aTask
			if theDuration is missing value then set theDuration to "60"
			set theURI to "omnifocus:///task/" & id of aTask
			
			tell application "Calendar"
				make new event at end of events of calendar theCal with properties {summary:theAction, start date:theStart, end date:theStart + (theDuration * minutes), url:theURI}
			end tell
			
		end repeat
	end tell
end tell

EDIT: I just noticed that in the RESULTS box of the script editor, pops up with this message after running the script:

event id "41DE9C38-9B4F-4BF0-B6A3-D813F6294566" of calendar id "C7361304-C6FF-4C9E-BCBE-2D64AF88C1C1" of application "Calendar"

Don’t know if that means anything?

Hmm, did you select all three tasks at the same time and run the script once or select each task individually and run the script three times?

If the latter, this script can’t accommodate that. You need to select everything you want to schedule for today in a single shot and run the script once.

If the former, keep reading…

About the tasks:

  1. Defer date on all of them is today?
  2. Duration is blank?
  3. In OF Preferences > Date & Time, “Default Time for Defer Dates” is 9am?
  4. All the calendar appointments are being successfully created, yes? It’s just the start/end times are all the same?

Notes:
In Script Editor, Cmd+Shift+O (the letter that comes after “N”, not the number zero) will pull up a list of applications with available AppleScript dictionaries. It’s a bit like trying to read a foreign language but gives you insight in the terminology for a specific app and what commands are available. Open the OF dictionary and look up “task”, the list of properties will tell you that “estimated minutes” is the proper terminology to get the duration of the task, etc.

The AppleScript output of “event id…” is just telling you that the last process of the script created event …4566 in calendar …C1C1 in the Calendar application. Select the “Replies” window before running the script and you will see a bit more information as the script runs.

To achieve your final goal, it might actually be easier* to bypass Calendar altogether. You’re just looking to get calendar events as an email attachment to move them to your work system, right? Assuming you can’t share a separate calendar between your home and work systems, ICS files are just text files. A script could extract the data from OF (as we’re already doing), create a text file and save it as an ICS file, and send an email with the text file attachments.

*easier as in “more direct”, but the script itself would be a bit more complicated. ;-)

ok, first things first :)

I did select all three tasks and ran the script once.

1.defer date was today
2. duration was blank
3. yep
4. yep, all calendar events successfully created, they just didn’t get staggered.

It does make sense to me, as they all have “starting time” set to 9am - why would the script not pop them there? Nothing says, “if 9am is occupied, pop it down to 10am”. hm.

ok, so maybe I need to explain my final goal (and this is somewhat a work in progress as I haven’t got it to work and therefore I can’t test that that’s what actually works…)

I can happily ignore my task manager, regardless of its notifications and badges, rarely opening it at times other than when I plan a project and input all the tasks. however, i rarely ignore my calendar, and email. So, my thinking is, to save me from myself, to build a belt-and-suspenders system of not being able to not see my tasks :)

Practical example, let’s say I need to write a journal article and I map out the individual steps and when I need to start them to have them finished by date X. A lot of these tasks will be un-GTD in that there are largish (e.g. write introduction), so will take me probably a few days, and I would usually expect to need a 1-hour block to work on it. (I will map out smaller tasks when I am actually working on the introduction, but they will likely be on a piece of paper because putting them into OF will mean managing my tasks rather than doing them).

Now that I have the project set up, I run the script and it puts in all the future events (on their defer dates). On the day that I have said I need to start, for example, the introduction, a second script will (automatically) send me an email saying “Hey you should be starting on your introduction (and these other tasks from other projects)”. Because they are in my calendar, I will then go to my calendar, look at my week, and find suitable 1-hour spots to drag my task into (and make copies of the event as necessary to distribute throughout the rest of the week). Does this make sense?

Now, this is the ideal version, trying to make myself more organised and give me cues as to when I need to start on something. It would be nice if the task event in the calendar had extra info (in a readable format) such as when it’s due or if I have a link saved with it. Or a tag if I need to alert myself that I need particular things to do the task (eg. @computer) But that’s not vital. Who knows, I might even be tempted to open my task manager to look at this extra-info :)

Oh, yeah, you are right, I am on PC at work (Office 365/Exchange) and at home I am on Mac (iCal and Mail for personal use, Outlook for work stuff). I don’t really mind which calendar the events end up in, but I guess, the work calendar makes the most sense. So, the difficulty is not in moving them, but in reminding me to do stuff :)

Thank you for your help and for explaining the dictionary - I will have a look, and perhaps scripting will be a bit more demystified…

Oh, son of a &^%^. This is the love/hate relationship I have with coding…the high you get from discovering the solution is negated by the “why the hell didn’t I see that 12 hours ago” feeling of inadequacy!

Add this line right before “end repeat”
set today to today + 60 * minutes

Funnily enough, that is the direction I started going this morning but then thought I was making more work for myself.
#facepalm

LOL, that sounds more like belt and suspenders when you’re already wearing pants with an elastic waistband. ;-)
But I like where you’re going. The reason I was able to produce this script so easily 4 years ago is because I make use of a couple of scripts to schedule my tasks to either iCal or Reminders. I look at my Next Actions, select a few, and shoot them to Reminders so I get an alarm when it’s time to move on.

With that explanation then, no, my idea of bypassing Calendar won’t work. What I’d recommend is pushing the tasks to your Calendar when you project plan and then have a second script that fires every morning and scrapes OF to what’s starting today (and due soon?) for the reminder email.

You can add more data to the, what should now be working, Calendar events. Any data that exists in the task can be written to the Calendar event in the description field. The OF due date, context, notes, etc. can all be scraped in the “set [this] to [this] of aTask” section of the script, just add more fields. (While you’re at it, you can remove or comment out the “theURI” line and remove the “url:theURI” from the “make new event” line, the direct OF link won’t work on your PC.)

This should get you pointed in the right direction, but let me know if you need more help:

set theNotes to note of aTask
set theDue to due date of aTask
set theProject to container of aTask

set calNotes to "Project: " & theProject & return & "Due: " & theDue & return & theNotes

make new event... {...description: calNotes}

Or, you could put the due date in the title with something like
set theSum to theAction & " Due: " & theDue