Find recurring event that has an item within date range

I am trying to make a mirror of one calendar into another for the a set period of time (say 1 week). However when I run the script below it only copies non-recurring events. Any pointers on how to fix this is much appreciated


use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions

set SourceCalendarName to " VV Main"
set DestinationCalendarName to "VV Mirror"
set meetingProxy to "VV Meeting"
set today to current date

set numberofdays to 7
set startDay to ((current date) - (1 * days))
set time of startDay to 0
set endDay to ((startDay) + (numberofdays * days))
--set time of endDay to 

set numberOfEventsAdded to 0



tell application "Calendar"
	
	set sourceCalendar to calendar SourceCalendarName
	set destinationCalendar to calendar DestinationCalendarName
	
	(*
	tell destinationCalendar
		delete (events)
	end tell
	*)
	
	set sourceEventList to (events of sourceCalendar where (its start date > startDay) and (its start date < endDay))
	
	repeat with eventIdx from 1 to length of sourceEventList
		
		set newEvent to item eventIdx of sourceEventList
		
		--repeat with newEvent in (get events of sourceCalendar whose (start date is greater than startDay) and (start date is less than endDay))
		
		set existingEventList to (events of destinationCalendar)
		
		set eventExists to false
		
		if length of existingEventList is not 0 then
			repeat with checkEvent in existingEventList
				
				if ((start date of checkEvent = start date of newEvent) and (end date of checkEvent = end date of newEvent)) then
					set eventExists to true
					exit repeat
				end if
				
			end repeat
		end if
		
		if eventExists is false then
			tell destinationCalendar
				set destEvent to (make new event at end of events with properties {start date:start date of newEvent, end date:end date of newEvent, summary:meetingProxy, allday event:allday event of newEvent, description:(uid of newEvent as text)})
				if recurrence of destEvent is not missing value then
					set recurrence of destEvent to recurrence of newEvent
				end if
				
			end tell
		end if
		
		--set numberOfEventsAdded to (numberOfEventsAdded + 1)
		
		
	end repeat
end tell

I think your problem is the line:

	set sourceEventList to (events of sourceCalendar **where (its start date > startDay)** and (its start date < endDay))

The ‘start date’ value for recurring events is the first time that event occurs, which may have been weeks or months prior to your startDay variable, and therefore is excluded. They are not added to the calendar as individual entities.

All is not lost. Events have a ‘recurrence’ property. You can query this property to capture recurring events (although you’ll need to parse the data to see if the event is still current)

1 Like

Interesting, I imagined some of the sorts. I understand i need to check the recurrence property, but how do I go about checking if there is a recurrence event present within my date range?

That is a task which I don’t envy you for :slight_smile:

Specifically, the ‘recurring’ property will have something like:

“FREQ=WEEKLY;INTERVAL=1;UNTIL=20250531T065959Z;BYDAY=FR,TU”

Here you can see the selected event occurs weekly (“FREQ=WEEKLY”) on Tuesdays and Fridays (“BYDAY=FR,TU”) until May 31st 2025 (“UNTIL=20250531T065959Z”)

You’d need to compare those values to the current startDay and endDay variables to determine if there’s an overlap. Not a trivial task.

The actual contents of this field can contain multiple levels of detail, as described in RFC 2445.

Would be much easier if you could simply ask Calendar.app for a list of events on a given day, regardless of calendar/recurrence/etc., but it doesn’t do that.

1 Like

Hi @vmax.

Shane’s “CalendarLib EC” library could help here. When fetching events in a specified date range, it takes recurring events’ expression dates into account, not just the dates of their root instances. After that, you can either get to grips with the library in earnest and use it to create the new events or, as below, use the Calendar application for expedience.

use AppleScript version "2.4" -- Yosemite (10.10) or later
use script "CalendarLib EC" version "1.1.5"
use scripting additions

set SourceCalendarName to " VV Main"
set DestinationCalendarName to "VV Mirror"
set meetingProxy to "VV Meeting"
set today to current date

set numberofdays to 7
set startDay to (today - (1 * days))
set time of startDay to 0
set endDay to (startDay + (numberofdays * days))

set numberOfEventsAdded to 0

set theStore to (fetch store)
-- The original script only compares events' start and end dates.
-- Get a list of the start and end dates of the destination calendar's existing events which occur
-- between startDay and endDay, including the expression dates of any recurring events.
set destCal to (fetch calendar DestinationCalendarName cal type cal cloud event store theStore) -- change calendar type to suit
set existingEventList to (fetch events starting date startDay ending date endDay searching cals {destCal} event store theStore)
repeat with thisEvent in existingEventList
	set {event_start_date:startDate, event_end_date:endDate} to (event info for event thisEvent)
	set thisEvent's contents to {startDate, endDate}
end repeat
set existingEventDates to existingEventList -- Use a different variable now for clarity.

-- Get the source calendar events which fall within the same date range.
set sourceCal to (fetch calendar SourceCalendarName cal type cal cloud event store theStore) -- change to suit
set sourceEventList to (fetch events starting date startDay ending date endDay searching cals {sourceCal} event store theStore)
repeat with newEvent in sourceEventList
	-- Get the data of interest for each source event.
	set {event_external_ID:eventID, event_start_date:startDate, event_end_date:endDate, all_day:isAllday, event_is_recurring:isRecurring} to (event info for event newEvent)
	-- If its start and end dates aren't in existingEventDates, create a new event using the Calendar appplication..
	if (existingEventDates does not contain {{startDate, endDate}}) then
		tell application "Calendar"
			set destEvent to (make new event at end of calendar DestinationCalendarName's events with properties {start date:startDate, end date:endDate, summary:meetingProxy, allday event:isAllday, description:eventID})
			if (isRecurring) then
				set destEvent's recurrence to recurrence of event id eventID of calendar SourceCalendarName
			end if
			set end of existingEventDates to {startDate, endDate} -- if required
			set numberOfEventsAdded to numberOfEventsAdded + 1
		end tell
	end if
end repeat
1 Like


The culprit seems to be iCal’s that were imported, fwiw

Hi @vmax.

No. You’ve confused me a bit. The code in the first picture is different from what I posted and, while the highlighted line is AppleScript directed at Calendar, the error message is an Objective-C one. :confused:

I presume the changed code is because you’ve found that startDate is occasionally being returned as missing value for some reason. I can’t think why this should be. startDate’s value at that point is from one of the source calendar events, so it’s not being incorrectly set by the script.

I did notice when writing the script that if I made a mistake in the code which caused it to crash, it would often continue to crash even after being corrected. This may have been due to corruption of the loaded instance of the library. To clear the problem, I had to copy the code to the clipboard, quit and reopen the editor, and paste the code back into a new window.

That’s all I can think of at the moment. :confused:

Apologies! was trying to figure out where the issue was coming from and copied the wrong screenshot

when i run the code you provided, here is where it gets stuck

This seems to work. Looks like the “Creation date missing” error is something Shane is aware of. So i made a sloppy solution of ignoring the error if it does [ANN] CalendarLib, improved Calendar scripting - #20 by vmax

use script "CalendarLib EC" version "1.1.5"
use AppleScript version "2.4" -- Yosemite (10.10) or later

use scripting additions

set SourceCalendarName to "VV Main"
set DestinationCalendarName to "VV Mirror"
set meetingProxy to "VV Meeting"
set today to current date

set numberofdays to 7
set startDay to (today)
set time of startDay to 0
set endDay to (startDay + (numberofdays * days))

set numberOfEventsAdded to 0
set numberofEventsFailedtoCopy to 0

set theStore to (fetch store)
-- The original script only compares events' start and end dates.
set destCal to (fetch calendar DestinationCalendarName cal type cal cloud event store theStore) -- change calendar type to suit
set existingEventList to (fetch events starting date startDay ending date endDay searching cals {destCal} event store theStore)

repeat with thisEvent in existingEventList
	set {event_start_date:startDate, event_end_date:endDate} to (event info for event thisEvent)
	set thisEvent's contents to {startDate, endDate}
end repeat

set existingEventDates to existingEventList -- Use a different variable now for clarity.

-- Get the source calendar events which fall within the same date range.
set sourceCal to (fetch calendar SourceCalendarName cal type cal cloud event store theStore) -- change to suit
set sourceEventList to (fetch events starting date startDay ending date endDay searching cals {sourceCal} event store theStore)
repeat with eventIdx from 1 to length of sourceEventList
	set newEvent to item eventIdx of sourceEventList
	-- Get the data of interest for each source event.\
	try
		set {event_external_ID:eventID, event_start_date:startDate, event_end_date:endDate, all_day:isAllday, event_is_recurring:isRecurring} to (event info for event newEvent) (*

		-- If its start and end dates aren't in existingEventDates, create a new event using the Calendar appplication..
		if (existingEventDates does not contain {{startDate, endDate}}) then
			
			tell application "Calendar"
				set destEvent to (make new event at end of calendar DestinationCalendarName's events with properties {start date:startDate, end date:endDate, summary:meetingProxy, allday event:isAllday})
				if (isRecurring) then
					set destEvent's recurrence to recurrence of event id eventID of calendar SourceCalendarName
				end if
				set end of existingEventDates to {startDate, endDate} -- if required
				set numberOfEventsAdded to numberOfEventsAdded + 1
			end tell
			
		end if
		
	on error errMsg number -10000 --*** -L_NSDictionaryM setObject:forKey:]: object cannot be nil (key: event_creation_date) 
		set eventIdx to {eventIdx + 1}
		set numberofEventsFailedtoCopy to (numberofEventsFailedtoCopy + 1)
		
	end try
	
end repeat