Sort iCal Events by Start Date


Goal: Generate a text file (for printing) which contains a sorted list of iCal events (sorted by start date).

When asking iCal for a list of events, the result is not necessarily sorted by start date (I don’t know what criteria is used to determine the order of the list). Does anyone have a handler (that you care to share) that will sort a list of iCal events by start date? I can likely stumble through this but I’ve been fumbling around without success and I need this yesterday. I would truly appreciate it if someone offers code or guidance to this tired ol’ scripter.

set sorted_ to {}

tell application "iCal"
	set events_ to events of calendar 1
	repeat with event_ in events_
		-- brain fart
		-- determine that latest date in events_ and add it to end of sorted_ for further processing
	end repeat
end tell

Note: I plan to limit the list of events to those which fall within the current month but I can handle that part as well as generating the text file. It’s simply the sorting that’s causing my brain fart.


Did anyone have any thoughts on this one as I need to do the same thing!



This thread might be of use to you:

I generate three lists (this is just a fragment of a larger script) sort them together on days to go and growl the output:

-- This script calculates the days remaining before the next four birthdays in an iCal calendar named "Birthdays".
-- Each birthday is entered as an all day event
-- The script uses Growl to display the result.

-- Get today's date with time set to midnight. Later days to go subtractions must have a time of day in common or differences can be off by one day.
set today to current date
set time of today to 0 -- seconds after midnight

--  Get the Birthday Date List "bDays" and Birthday Name List "bName", correct for GMT, then subtract today after correcting year.
tell application "iCal"
	close window 1
	set bdCals to every calendar whose title contains "Birthdays"
	set bCal to first item of bdCals
	set toGo to {}
	set who to {}
	set when to {}
	-- Collect the date/name lists
	set bCount to count events of bCal
	repeat with n from 1 to bCount
		-- Start date is the birthday for an all day event. 
		-- Summary should be the person's name.
		-- iCal stores times of events in GMT even though it presents them in local time. 
		-- Times must be shifted back to a midnight base before days to go are calculated.
		tell event n of bCal to set {tName, tDate} to {summary of it, start date of it}
		-- adjust for GMT offset
		tell tDate
			if time of it = 75600 then -- 9:00 PM if ADST
				set time of it to (time of it) + 10800
			else -- 8:00 PM if AST
				set time of it to (time of it) + 14400
			end if
			-- adjust the calendar year of the birthday ahead of now
			repeat until (it - today) > 0
				set year of it to (year of it) + 1
			end repeat
			-- Calculate days to go to next birthday
			set daysLeft to ((it - today) / days) as integer
			--set item n of tDate to daysLeft
			set end of toGo to daysLeft
			set end of who to tName
			set end of when to it
		end tell
	end repeat
end tell

-- Sort by days to go
sort_items(toGo, who, when)

-- Get first four
set msg_C to " days until "
set BDNotes to ""
set r to return
set rr to r & r
set sp to space
set ap to ASCII character 240
repeat with mm from 1 to 5
	set msg_A to (item mm of toGo) as text
	set msg_B to (item mm of who)
	set msg_D to date string of (item mm of when)
	-- add possessives for names: soAndso's Birthday
	if last character of msg_B = "s" then
		set msg_B to msg_B & "'"
		set msg_B to msg_B & "'s"
	end if
	if msg_B = "Anniversary's" then set msg_B to "Our Anniversary"
	set tBDNote to msg_A & msg_C & msg_B & " on" & r & ap & sp & sp & msg_D
	set BDNotes to BDNotes & tBDNote & rr
end repeat

Growl_It("Birthdays Coming Soon", BDNotes)

to sort_items(sortList, SecondList, thirdList) -- by Kai Edwards
	tell (count sortList) to repeat with i from (it - 1) to 1 by -1
		set s to sortList's item i
		set r to SecondList's item i
		set q to thirdList's item i
		repeat with i from (i + 1) to it
			tell sortList's item i to if s > it then
				set sortList's item (i - 1) to it
				set SecondList's item (i - 1) to SecondList's item i
				set thirdList's item (i - 1) to thirdList's item i
				set sortList's item (i - 1) to s
				set SecondList's item (i - 1) to r
				set thirdList's item (i - 1) to q
				exit repeat
			end if
		end repeat
		if it is i and s > sortList's end then
			set sortList's item it to s
			set SecondList's item it to r
			set thirdList's item it to q
		end if
	end repeat
end sort_items

on Growl_It(gTitle, gMessage)
	tell application "GrowlHelperApp"
		notify with name "Next4BD" title gTitle description (return & gMessage) application name "Birthdays" with sticky
	end tell
end Growl_It

Yet another approach is to extract the information you want from the events you want sorted, put them into a list, and use a bubblesort to sort the list. With the list then sorted, you can present the data any way you choose. For instance, this script extracts just the start date and the summary of every event from a calendar later than today and then displays it in a TextEdit document:

set ev_List to {}
tell application "iCal"
	set some_events to every event of calendar "SpanawayWard" whose start date > (current date) --and start date < ((current date) + 30 * days)
	repeat with x in my some_events
		set end of ev_List to {x's start date, x's summary}
	end repeat
end tell

repeat with i from length of ev_List to 2 by -1 --> go backwards
	repeat with j from 1 to i - 1 --> go forwards
		tell ev_List
			if (item j)'s item 1 > (item (j + 1))'s item 1 then
				set {item j, item (j + 1)} to {item (j + 1), item j} -- swap
			end if
		end tell
	end repeat
end repeat

to MakeText(xx)
	set txt to ""
	repeat with x in xx
		set txt to txt & (x's item 1 as string) & space & (x's item 2) & return
	end repeat
	tell application "TextEdit" to make new document with properties {text:txt}
end MakeText

In my calendar, 90 events sorted in 6 seconds, while taking over 2 minutes on Kim Hunter’s script (link posted in 3rd message above). I have not tried Adam’s script yet.

Thanks to everyone for their feedback.

The last option errors for me on both Panther and Tiger.

Panther: iCal got an error: NSReceiverEvaluationScriptError: 4
Tiger: ev_List not defined


Model: PowerMac
AppleScript: 2.0 (v43.1)
Browser: Safari 312.6
Operating System: Mac OS X (10.3.9)

Whoops. I thought I had copied it clean; I forgot to set ev_List to an empty list at the beginning of the script. It is now edited and correct.

Thanks a bunch craig,

This was the sort of solution I was hunting for.

Works perfectly on tiger, but I still get ‘NSReceiverEvaluationScriptError: 4’ from Panther.

Any further thoughts.


Don’t worry.

I figured it out. Just had to change how it calls for the event list.

Thanks everyone for all your help.