OK. See how this goes. This time, the calendar name property to edit to your requirements is calendarList, which must be a list containing the relevant calendar name(s).
-- Faster version using ASObjC.
-- Requires Shane Stanley's CalendarLib library. (Use the EC version with El Capitan.)
-- <[url=http://www.macosxautomation.com/applescript/apps/Script_Libs.html]www.macosxautomation.com/applescript/apps/Script_Libs.html[/url]>.
-- Doesn't require Calendar.app to be running.
-- Includes the expression dates of repeating events.
-- Now has a policy for the handling of all-day and multi-day events.
-- This version simply (!) lists events one per line and saves the resulting text to a file on the user's desktop.
-- Tested with CalendarLIb EC in Mac OS 10.11.5.
use script "CalendarLib EC"
use scripting additions
property calendarList : {"Home", "Work"} -- Edit as required. An empty list means all calendars.
main()
on main()
set {dateRangeStart, dateRangeEnd} to getDateRange()
set dataList to my fetchEventsStarting:dateRangeStart ending:dateRangeEnd
set eventText to composeText(dataList)
set fileName to "Event list " & short date string of dateRangeStart & "-" & short date string of dateRangeEnd & ".txt"
saveToFile(eventText, fileName)
set userReaction to button returned of (display dialog "The event information has been saved to a file called “" & fileName & "” on your desktop." with icon note buttons {"Reveal", "Open", "Thanks!"} default button 3)
if (userReaction is "Reveal") then
tell application "Finder"
activate
reveal file fileName of desktop
end tell
else if (userReaction is "Open") then
tell application "Finder" to open file fileName of desktop
end if
end main
-- Shane's handler to get the event data using his library, modified for special handling of all-day and multi-day events.
on fetchEventsStarting:dateRangeStart ending:dateRangeEnd
-- 'fetch store', 'fetch calendars', and 'fetch events' are from CalendarLib.
set theStore to (fetch store)
set theCals to (fetch calendars calendarList cal type list {} event store theStore)
-- It's come to light that the system method which fetches the events won't get more than four years of them at a time. CalendarLib will no doubt be updated to work round this in time, but here's a work-round anyway.
set theEvents to {}
set fromDate to dateRangeStart
set toDate to fromDate - 1
set justUnderFourYears to (365 * 4) * days
repeat until (fromDate comes after dateRangeEnd)
set toDate to toDate + justUnderFourYears
if (toDate comes after dateRangeEnd) then set toDate to dateRangeEnd
set theEvents to theEvents & (fetch events starting date fromDate ending date toDate searching cals theCals event store theStore)
set fromDate to fromDate + justUnderFourYears
end repeat
script o
property dataList : {}
end script
repeat with anEvent in theEvents
-- Get the start date, end date, time zone, and summary of each returned event.
set {event_start_date:thisStartDate, event_end_date:thisEndDate, event_time_zone:thisTimeZone, event_summary:thisSummary} to (event info for event anEvent) -- CalendarLib.
-- If a returned event starts before the date range entered by the user, note the fact and set its start date to that of the range.
set startedBeforePeriod to (thisStartDate comes before dateRangeStart)
if (startedBeforePeriod) then set thisStartDate to dateRangeStart
-- With an all-day event (no associated time zone), nudge its end time forward by a second to 23:59:59 on the event day.
set allDayEvent to (thisTimeZone is missing value)
if (allDayEvent) then set thisEndDate to thisEndDate - 1
-- Store the start date, 'already started' flag, end date, 'all-day event' flag, and summary. If a multi-day event, add discrete entries for each date it occupies in the range.
repeat until ((thisStartDate comes after thisEndDate) or (thisStartDate comes after dateRangeEnd))
set end of o's dataList to {thisStartDate, startedBeforePeriod, thisEndDate, allDayEvent, thisSummary}
set thisStartDate to thisStartDate + days
set thisStartDate's time to 0
set startedBeforePeriod to true
end repeat
end repeat
-- Sort the entries by start date.
sortByStartDate(o's dataList)
return o's dataList
end fetchEventsStarting:ending:
-- Sort the filtered data by start date.
on sortByStartDate(dataList)
-- Comparison object for a customisable sort. Compares the first items of two passed lists.
script byFirstListItem
on isGreater(a, b)
return (beginning of a > beginning of b)
end isGreater
end script
CustomInsertionSort(dataList, 1, -1, {comparer:byFirstListItem})
end sortByStartDate
-- Customisable insertion sort. Algorithm: unknown author. AppleScript implementation: Arthur J. Knapp and Nigel Garvey, 2003. Revised by NG, 2010.
on CustomInsertionSort(theList, l, r, customiser)
script o
property comparer : me
property slave : me
property lst : theList
on isrt(l, r)
set u to item l of o's lst
repeat with j from (l + 1) to r
set v to item j of o's lst
if (comparer's isGreater(u, v)) then
set here to l
set item j of o's lst to u
repeat with i from (j - 2) to l by -1
tell item i of o's lst
if (comparer's isGreater(it, v)) then
set item (i + 1) of o's lst to it
else
set here to i + 1
exit repeat
end if
end tell
end repeat
set item here of o's lst to v
slave's rotate(here, j)
else
set u to v
end if
end repeat
end isrt
on isGreater(a, b)
(a > b)
end isGreater
on rotate(a, b)
end rotate
end script
set listLen to (count theList)
if (listLen > 1) then
if (l < 0) then set l to listLen + l + 1
if (r < 0) then set r to listLen + r + 1
if (l > r) then set {l, r} to {r, l}
if (customiser's class is record) then set {comparer:o's comparer, slave:o's slave} to (customiser & {comparer:o, slave:o})
o's isrt(l, r)
end if
return -- nothing.
end CustomInsertionSort
-- Ask the user for the range of dates to be covered.
on getDateRange()
set today to (current date)
set d1 to today's short date string
set d2 to short date string of (today + 6 * days)
set dateRange to text returned of (display dialog "Enter the required date range:" default answer d1 & " - " & d2)
set dateRangeStart to date (text from word 1 to word 3 of dateRange)
set dateRangeEnd to date (text from word -3 to word -1 of dateRange)
set dateRangeEnd's time to days - 1 -- Sets the last date's time to 23:59:59, the last second of the range.
return {dateRangeStart, dateRangeEnd}
end getDateRange
-- Derive a text from the gathered data.
on composeText(dataList)
-- dataList = list of {{thisStartDate, startedBeforePeriod, thisEndDate, allDayEvent, thisSummary}, {thisStartDate, …
if (dataList is {}) then
return "No events found in this period."
else
script o
property workList : dataList
end script
repeat with i from 1 to (count dataList)
-- Get the data for an event/day from the list of filtered data.
set {{date string:thisCalendarStartDate, hours:thisStartTimeH, minutes:thisStartTimeM}, startedBeforeToday, {date string:thisCalendarEndDate, hours:thisEndTimeH, minutes:thisEndTimeM}, allDayEvent, thisSummary} to item i of o's workList
set endsAfterToday to (thisCalendarEndDate is not thisCalendarStartDate)
-- Begin the entry for the event/day with a suitable expression of its start date.
set thisEntry to thisCalendarStartDate
if (startedBeforeToday) then
set thisEntry to thisEntry & " (already started, ends "
else if (not allDayEvent) then
tell (10000 + thisStartTimeH * 100 + thisStartTimeM) as text to set thisStartTime to space & text 2 thru 3 & ":" & text 4 thru 5
set thisEntry to thisEntry & thisStartTime & "-"
else if (endsAfterToday) then
set thisEntry to thisEntry & "-"
end if
-- If appropriate, append a suitable expression of the end time.
if (endsAfterToday) then
set thisEntry to thisEntry & thisCalendarEndDate
else if (startedBeforeToday) then
set thisEntry to thisEntry & "today"
end if
if (not allDayEvent) then
tell (10000 + thisEndTimeH * 100 + thisEndTimeM) as text to set thisEndTime to text 2 thru 3 & ":" & text 4 thru 5
if ((startedBeforeToday) or (endsAfterToday)) then set thisEndTime to space & thisEndTime
set thisEntry to thisEntry & thisEndTime
end if
if (startedBeforeToday) then set thisEntry to thisEntry & ")"
-- Append a tab and the event's summary.
set thisEntry to thisEntry & (tab & thisSummary)
-- Store this entry.
set item i of o's workList to thisEntry
end repeat
-- When all the entries are ready, coerce to a single text with linefeeds and return the result.
set astid to AppleScript's text item delimiters
set AppleScript's text item delimiters to linefeed
set outputText to o's workList as text
set AppleScript's text item delimiters to astid
return outputText
end if
end composeText
-- Save the text to a file on the desktop.
on saveToFile(txt, fileName)
set filePath to (path to desktop as text) & fileName
set fRef to (open for access file filePath with write permission)
try
set eof fRef to 0
write txt as «class utf8» to fRef
close access fRef
on error errMsg
close access fRef
display dialog errMsg with icon stop buttons {"OK"} default button 1
error number -128
end try
end saveToFile
Edits: Minor tidying up of script code and comments, minor bug fixes, work-round for just discovered “four year” bug in the system method CalendarLib uses to get the events.
27th October 2018: Characters corrupted in a later MacScripter BBS software update restored to the originals.