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
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)
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?
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.
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
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.
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.
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