Faster way to find a Calendar event

Hey,

With over 2000 events in this specifed calendar, the following script is taking around 15 seconds to find events between 9am today and 9am tomorrow.

Would anyone have a suggestion for a better solution?



set theDestCalendar to "Home - Jase"
set todaysDate to date ((date string of (current date)) & " 9:00:00 am")

tell application "Calendar"
	
	set theEvents to events of calendar theDestCalendar whose start date is greater than todaysDate and start date is less than or equal to (todaysDate + 86400)
		
	set eventTitle to summary of (item 1 of theEvents)
	
end tell


Thanks in advance gang. You’re awesome.

Jase

My opinion is that the only way to speed it up is to create a command-line app in Swift or Objective-C that can be fired from an AppleScript do shell script. The issue at hand is the increased security with the Calendar Store, and AppleScripts run by the user have no problems with that, but it takes time to compile, query, and perform a task, even with permission already granted.

Do you have any Objective-C or Swift ability?

Hi Craig,

Thank you kind for your response. I’m afraid your suggestion, whilst very helpful, are outside my knowledge base. :frowning: Maybe some time in the future but until then, slowness it is for me!

Cheers,

Jase

What version of the OS are you running?

Why, when you can use AppleScriptObjC?

This script requires Yosemite or later, or it can be put in a script library and run in Mavericks. On my Mac, searching a calendar with 8000+ entries, it takes about a tenth of a second to return the titles.

use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "EventKit"

set listOfCalNames to {"Home - Jase"} -- list of one or more calendar names
set listOfCaTypes to {0} -- list of one or more calendar types: : Local = 0, CalDAV/iCloud = 1, Exchange = 2, Subscription = 3, Birthday = 4
-- create start date and end date for occurances
set nowDate to current application's NSDate's |date|()
set todaysDate to current application's NSCalendar's currentCalendar()'s dateBySettingHour:9 minute:0 |second|:0 ofDate:nowDate options:0
set tomorrowsDate to todaysDate's dateByAddingTimeInterval:1 * days

-- create event store and get the OK to access Calendars
set theEKEventStore to current application's EKEventStore's alloc()'s init()
theEKEventStore's requestAccessToEntityType:0 completion:(missing value)

-- check if app has access; this will still occur the first time you OK authorization
set authorizationStatus to current application's EKEventStore's authorizationStatusForEntityType:0 -- work around enum bug
if authorizationStatus is not 3 then
	display dialog "Access must be given in System Preferences" & linefeed & "-> Security & Privacy first." buttons {"OK"} default button 1
	tell application "System Preferences"
		activate
		tell pane id "com.apple.preference.security" to reveal anchor "Privacy"
	end tell
	error number -128
end if

-- get calendars that can store events
set theCalendars to theEKEventStore's calendarsForEntityType:0
-- filter out the one you want
set theNSPredicate to current application's NSPredicate's predicateWithFormat_("title IN %@ AND type IN %@", listOfCalNames, listOfCaTypes)
set calsToSearch to theCalendars's filteredArrayUsingPredicate:theNSPredicate
if count of calsToSearch < 1 then error "No such calendar(s)."

-- find matching events
set thePred to theEKEventStore's predicateForEventsWithStartDate:todaysDate endDate:tomorrowsDate calendars:calsToSearch
set theEvents to (theEKEventStore's eventsMatchingPredicate:thePred)
-- sort by date
set theEvents to theEvents's sortedArrayUsingSelector:"compareStartDateWithEvent:"
-- return title property, called summary in AS, for them all
return (theEvents's valueForKey:"title") as list

Edited to add error if calendar not found, and control over type of calendar(s) to search.

Using Shane’s script, I attempted to find the most recent calendar event in a calendar named “Home” whose event occurred in the last 10 seconds. I was however unable to confine the search:

–either by time
Although I set the time to - 10 seconds, the script found set included a larger time scope.

–or by calendar name
Although I included the “Home” calendar name in the predicate, the script found events in other calendars.

use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "EventKit"

set listOfCalNames to {"Home"} -- list of one or more calendar names
-- create end date for occurences
set nowDate to current application's NSDate's |date|()

--create start date  to 10 seconds  before script executes
set PreviousSeconds to todaysDate's dateByAddingTimeInterval:-10

--gain access to Event Kit. 
set theEKEventStore to create_event_store_access()

--if no access is allowed to Event Kit, then exit script
if theEKEventStore is false then return

-- get calendars that can store events
set theCalendars to theEKEventStore's calendarsForEntityType:0

-- filter the find to events in the  calendar  named "Home"
set theNSPredicate to current application's NSPredicate's predicateWithFormat_("title IN %@", listOfCalNames)
set calsToSearch to theCalendars's filteredArrayUsingPredicate:theNSPredicate

-- find matching events in the past 10 seconds
set thePred to theEKEventStore's predicateForEventsWithStartDate: PreviousSeconds endDate:nowDate calendars:calsToSearch
set theEvents to (theEKEventStore's eventsMatchingPredicate:thePred)

-- sort by date
set theEvents to theEvents's sortedArrayUsingSelector:"compareStartDateWithEvent:"

-- return title property, called summary in AS, for most recent events
return last item of (theEvents's valueForKey:"title") as list


--sub routine to gain access to  Event Kit
on create_event_store_access()

	-- create event store and get the OK to access Calendars
	set theEKEventStore to current application's EKEventStore's alloc()'s init()
	theEKEventStore's requestAccessToEntityType:0 completion:(missing value)
	
	-- check if app has access; this will still occur the first time you OK authorization
	set authorizationStatus to current application's EKEventStore's authorizationStatusForEntityType:0 -- work around enum bug
	if authorizationStatus is not 3 then
		display dialog "Access must be given in System Preferences" & linefeed & "-> Security & Privacy first." buttons {"OK"} default button 1
		tell application "System Preferences"
			activate
			tell pane id "com.apple.preference.security" to reveal anchor "Privacy"
		end tell
		error number -128
		false
	else
		theEKEventStore
	end if
end create_event_store_access

How can I confine a found event to one calendar and to the last ten seconds?

Your version won’t run for me: The variable todaysDate is not defined. When I change it to nowDate, it runs. Could it be that you have todaysDate set somewhere else?

That said, what do you mean by the found set “included a larger time scope”? Do you mean it included events covering that period?

When you say “other calendars”, do you mean other calendars not named “Home”, or do you mean it doesn’t distinguish between local and iCloud calendars?

Shane,

The script now works and finds events confined to a period within 10 seconds of the end date of the event in the “Home” calendar on a local drive.

Thank you for your correction.

One thing to be aware of is that if you get the calendar name wrong, it will search all calendars.

Great point and easy error to happen with a string!

I guess that an error capture function would be useful in this code, so that if the calendar name is not found, then a choose dialog displays with the available calendar names, and then quits after a given amount of time if no choice has been responded to by the user.

Thanks for your help.

I’ve edited the script to include an error when the specified calendar(s) can’t be found, plus the ability to specify what sort of calendar(s) (local, iCloud, etc).

Shane,

Thanks for this script which is very much faster than the Applescript method !

But, it seems he doesn’t see the “Delegated” calendars on my Mac (which are also “read only”, I don’t know if it matters).
I tried to modify your script without success…

Do you have any idea ?

I know it’s a very old topic, but this would help me a lot !

Thanks
Regis

Alas, no.

Damn, thanks