Printing iCal Events

Found an old topic here: AppleScript to create list of Events over a specified date range

What I’m trying to do is have the script print out a list of “Family Events.”

Here’s the script as I’ve modified it.

-- 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

-- Return the start dates and summaries which are in the given date range.
on filterToDateRange(theStartDates, theSummaries, dateRangeStart, dateRangeEnd)
	set {eventDatesInRange, eventSummariesInRange} to {{}, {}}
	repeat with i from 1 to (count theStartDates)
		set thisStartDate to item i of theStartDates
		if (not ((thisStartDate comes before dateRangeStart) or (thisStartDate comes after dateRangeEnd))) then
			set end of eventDatesInRange to thisStartDate
			set end of eventSummariesInRange to item i of theSummaries
		end if
	end repeat
	return {eventDatesInRange, eventSummariesInRange}
end filterToDateRange

-- Sort both the start-date and summary lists by start date.
on sortByDate(eventDatesInRange, eventSummariesInRange)
	-- A sort-customisation object for sorting the summary list in parallel with the date list.
	script custom
		property summaries : eventSummariesInRange
		on swap(i, j)
			tell item i of my summaries
				set item i of my summaries to item j of my summaries
				set item j of my summaries to it
			end tell
		end swap
	end script
	CustomBubbleSort(eventDatesInRange, 1, -1, {slave:custom})
end sortByDate

-- CustomBubbleSort from "A Dose of Sorts" by Nigel Garvey.
-- The number of items to be sorted here is likely to be small.
on CustomBubbleSort(theList, l, r, customiser)
	script o
		property comparer : me
		property slave : me
		property lst : theList
		on bsrt(l, r)
			set l2 to l + 1
			repeat with j from r to l2 by -1
				set a to item l of o's lst
				repeat with i from l2 to j
					set b to item i of o's lst
					if (comparer's isGreater(a, b)) then
						set item (i - 1) of o's lst to b
						set item i of o's lst to a
						slave's swap(i - 1, i)
						set a to b
					end if
				end repeat
			end repeat
		end bsrt
		-- Default comparison and slave handlers for an ordinary sort.
		on isGreater(a, b)
			(a > b)
		end isGreater
		on swap(a, b)
		end swap
	end script
	-- Process the input parameters.
	set listLen to (count theList)
	if (listLen > 1) then
		-- Negative and/or transposed range indices.
		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}
		-- Supplied or default customisation scripts.
		if (customiser's class is record) then set {comparer:o's comparer, slave:o's slave} to (customiser & {comparer:o, slave:o})
		-- Do the sort.
		o's bsrt(l, r)
	end if
	return -- nothing 
end CustomBubbleSort

-- Compose the text from the items in the start-date and summary lists.
on composeText(eventDatesInRange, eventSummariesInRange)
	set txt to ""
	set gap to linefeed & linefeed
	repeat with i from 1 to (count eventDatesInRange)
		set txt to txt & (date string of item i of eventDatesInRange) & (linefeed & item i of eventSummariesInRange & gap)
	end repeat
	return text 1 thru -3 of txt
end composeText

on main()
	tell application "Calendar" to set {theStartDates, theSummaries} to {start date, summary} of events of calendar "Family Events"
	set {dateRangeStart, dateRangeEnd} to getDateRange()
	set {eventDatesInRange, eventSummariesInRange} to filterToDateRange(theStartDates, theSummaries, dateRangeStart, dateRangeEnd)
	sortByDate(eventDatesInRange, eventSummariesInRange)
	set txt to composeText(eventDatesInRange, eventSummariesInRange)
	tell application "TextEdit"
		make new document with properties {text:txt}
	end tell
end main


I get the following error:

Which happens here:
Screenshot 2

Any suggestions?


It looks as if you’re not getting any events with start dates between those you enter in getDateRange(). Either you’re specifying a period with no events or the period only contains repeated events. Unfortunately, Calendar’s scripting dictionary doesn’t give access to the expression dates of repeats of events, only to the start dates of the originals being repeated.

Nope, this is the date input window:

I needed to read your post more carefully . . . so what you’re saying is that unless I go back to the dates that the original events were created on (in some cases that could be 12 to 15 years) the script will find nothing.

I think I saw another older script during my search that dealt with the printing out of events. I’ll see if I can find that one.

You could check out Shane’s “CalendarLib EC” library, which I think can extract the dates you want. It can be downloaded from this page on the Late Night Software (ie. Script Debugger) site.

FWIW, this can be done with the Shortcuts app. As written, the shortcut prints those Calendar items in the next 31 days which have the title Family Events. However, this is easily changed to prompt the user for the title and dates. Some formatting of the text and error correction should be added.

Calendar Print.shortcut (22.6 KB)

1 Like

This is outstanding! Thank you.

First output was nothing (I’ve never played with Shortcuts). Played with a few of the drop down menu items, next output had at least dates. Added a few items into the “Title is” location, next output included dates, and folks names. Changed "where All’ to “where Any” and we’re in business. Output included the date, the event and who it was for. I may need to spend some time in the “Shortcuts” section.

Had one Family Event that just happened to be today, parents anniversary. Could not understand why “Start Date - Today + 365” would not have the anniversary in the text document. Until I looked at the Calendar app and saw that 2024 is a leap year, so adding that extra day (+ 366) did the trick.

The Calendar Print Shortcut produces a text file on the Desktop in this format:


I thought it would be good if the format was as follows:





I also thought it would be nice to export that file to Pages and have it saved as a PDF on the Desktop. For those who may be interested, the below script does just that.

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

set my_file to (choose file with prompt "Choose a text file")

tell application "Pages"
	set my_doc to open my_file
	tell my_doc to tell the body text
		set paragraph_list to (every paragraph)
		set number_of_paragraphs to (length of paragraph_list)
		repeat with n from number_of_paragraphs to 2 by -2
			set last character of paragraph n to (last character of paragraph n & linefeed)
		end repeat
		tell application "Pages"
			export document 1 ¬
				to file "MacBook HD:Users:homer:Desktop:Family Events.pdf" as PDF
			tell application "Pages"
				quit without saving
			end tell
		end tell
	end tell
end tell

Homer 712. If desired, you can accomplish the same thing (text formatting and PDF) with a shortcut without using the Pages app. My Calendar does not have an Event category, so I used the Note category instead. As before, you may have to fiddle with a few settings, but the shortcut worked as expected in my testing. BTW, the empty Text action is necessary to insert the blank line after the Note entry.

Calendar Print 1.shortcut (23.2 KB)

Thanks, as I was having issues with the whole “Pages” thing. If I started Pages and cleared out the “Open Recent” menu, the script would work perfectly. If I then tried it a second time, Pages would get stuck open as it had an unsaved file. Delete the file, open Pages again, clear the “Open Recent” menu and it would work perfectly again . . . once!

Spent the last five to six hours trying to figure out how to not just get the script to work (it does, perfectly) but how to quit Pages without having it nag about unsaved files. Totally frustrated.

I’m now using “peavine’s” second shortcut that does the PDF conversion and event spacing much more gracefully than any script that I could have come up with, thank you!

1 Like

Although this shortcut works great, I’m fiddling with a copy to see if I can get it to do something a bit different. I changed the date to “the next 365 days” and it produces a correct result. But that result is from today, 9/6/2023 to 9/5/2024. What I’m trying to do is have it produce a list for all of next year. So, from 1/1/2024 to 12/31/2024. I’ve tried endless combinations with no luck. Any help?

Homer712. You need to change the first part of the shortcut as shown in the screenshot below. I’ve also included the entire revised shortcut for download. A few comments:

  • There’s a simpler way to do this but it’s less flexible.
  • If a time is not specified, the shortcut uses midnight, and that’s why I used a start date of 12/31/23.
  • The dates in the Text actions assume a date format of month/day/year, and you should adjust to your computer’s date setting.
  • I tested this on my Ventura computer without issue.

Calendar Print 2.shortcut (23.6 KB)

I tried changing mine to match what I could see in your post, kept getting an error saying there were no events between the dates. Downloaded the one you posted, made the same changes that I’ve done before, and it working perfectly.

My project over tomorrow’s morning coffee is to put yours and my modified one side by side and see if I can spot what’s different and/or missing. The “learning” continues . . .

Thanks for you help.

Homer712. I mentioned above that there is a simpler method to set starting and ending dates, and I thought I would note how this is done:

  1. Delete the first four actions from the Calendar Print 2 shortcut. The Find Calendar Events action will now be at the top.
  2. Right-click on the first Dates parameter and select Ask Each Time.
  3. Right-click on second Dates parameter and select Ask Each Time.
  4. Run the shortcut and select the starting and ending dates in the Calendar dialog as shown below.

A third approach is to prompt the user for the start and end dates with one or two Ask for Input dialogs. I modified the earlier shortcut to work this way with one dialog.

Calendar Print 3.shortcut (23.9 KB)

Thanks for posting these. For what I’m looking to do, Calendar Print 2 works the best. Quick list, as a PDF file, and in chronological order. Works!

1 Like