Script: Create simple calendar event (without opening Calendar.app)

This script creates simple calendar events without the need to open Calendar.app.

It takes a natural language string as input, extracts the date and creates the event.

I use it with Alfred (Keyword and Run NSAppleScript actions), but it can be used with any app that provides text input. A display dialog with default answer would work too.

You need to download Shane’s CalendarLib EC. Thanks Shane!

-- Create simple calendar event

use AppleScript version "2.4"
use framework "Foundation"
use scripting additions
use script "CalendarLib EC" version "1.1.3"

property theCalendarName : "Privat" -- Set your calendar

set theQuery to "22:30 Fenster öffnen"
#set theQuery to "2022-09-20 18 Uhr Essen"
#set theQuery to "Montag Einkaufen!"

try
	set theString to (current application's NSString's stringWithString:theQuery)
	
	---------------------------------------------------------------- Extract date -----------------------------------------------------------------
	
	set theNSDataDetector to current application's NSDataDetector's dataDetectorWithTypes:(current application's NSTextCheckingTypeDate) |error|:(missing value)
	set theMatch to (theNSDataDetector's firstMatchInString:theString options:0 range:{location:0, |length|:theString's |length|()})
	if theMatch ≠ missing value then
		set theStartDate to theMatch's |date|() as date
		
		-------------------------------------------------- If date is in the past then use next day ---------------------------------------------------
		
		if theStartDate < (current date) then set theStartDate to theStartDate + 1 * days
		set theEndDate to theStartDate
		
		---------------------------------------------------------- Remove date from text -----------------------------------------------------------
		
		set theMatch_Range to theMatch's range()
		set theMatch_Range_Location to theMatch_Range's location
		set theMatch_String to theString's substringWithRange:theMatch_Range
		if (theMatch_Range_Location > 0) and (theMatch_Range_Location + (theMatch_Range's |length|()) ≠ theString's |length|()) then
			set theString_withoutFoundDate to my regexReplace(theString as string, " *" & theMatch_String & " *", space)
		else
			set theString_withoutFoundDate to my regexReplace(theString as string, " *" & theMatch_String & " *", "")
		end if
		
	else
		
		---------------------------------------------- If no date was provided then use current date -----------------------------------------------
		
		set theStartDate to current date
		set theEndDate to theStartDate
		set theString_withoutFoundDate to theString as string
	end if
	
	---------------------------------------------------------------- Create event -----------------------------------------------------------------
	
	set theStore to fetch store
	set theCalendar to fetch calendar theCalendarName cal type cal cloud event store theStore
	set theEvent to create event event store theStore destination calendar theCalendar event summary theString_withoutFoundDate starting date theStartDate ending date theEndDate
	store event event theEvent event store theStore
	
	---------------------------------------------------------------- Display dialog -----------------------------------------------------------------
	
	try
		set theIcon to POSIX file "/System/Library/PrivateFrameworks/CalendarUIKit.framework/Versions/A/Resources/App-empty.icns" as alias -- MS (12.5.1)
	on error
		set theIcon to POSIX file "/System/Applications/Calendar.app/Contents/Resources/App-empty.icns" as alias -- MBP (10.15.7)
	end try
	if theMatch ≠ missing value then
		set theDate_FormattatedText to my formatDateString(theStartDate)
		display dialog theString_withoutFoundDate & linefeed & theDate_FormattatedText with title "Created event" with icon theIcon
	else
		display dialog theString_withoutFoundDate & linefeed & "" with title "Created event" with icon theIcon
	end if
	
on error error_message number error_number
	activate
	if the error_number is not -128 then display alert "Error: \"Create event\"" message error_message as warning
	error number -128
end try

on regexReplace(theText, thePattern, theRepacement)
	try
		set theString to current application's NSString's stringWithString:theText
		set newString to theString's stringByReplacingOccurrencesOfString:(thePattern) withString:(theRepacement) options:(current application's NSRegularExpressionSearch) range:{location:0, |length|:length of theText}
		set newText to newString as string
	on error error_message number error_number
		activate
		if the error_number is not -128 then display alert "Error: Handler \"regexReplace\"" message error_message as warning
		error number -128
	end try
end regexReplace

on formatDateString(theDate)
	try
		set theDateFormatter to current application's NSDateFormatter's alloc()'s init()
		set theDateFormatter's timeZone to current application's NSTimeZone's localTimeZone()
		set theDateFormatter's locale to current application's NSLocale's currentLocale()
		set theDateFormatter's dateFormat to "yyyy-MM-dd 'um' HH:mm"
		set theDate_FormattatedText to (theDateFormatter's stringFromDate:theDate) as string
	on error error_message number error_number
		activate
		if the error_number is not -128 then display alert "Error: Handler \"formatDateString\"" message error_message as warning
		error number -128
	end try
end formatDateString

This looks interesting, Pete, but when I run it I get a -2700 error “No Calendar has been set”

Oops, I see it, I don’t have a “Privat” calendar, so I changed that to the name of my default calendar, and it worked!

Very cool!

Ahh, yes, forgot to mention that. I added a property. Thanks!

1 Like