Sorting Dates

Can dates be sorted as dates? I’ve tried a variety of sort routines and none of them seem reliable. I want to be able to sort something like this:

set theDates to {date "Thursday, June 1, 2006 12:00:00 AM", date "Tuesday, February 1, 2005 12:00:00 AM", date "Monday, May 1, 2006 12:00:00 AM", date "Sunday, December 25, 2005 12:00:00 AM", date "Sunday, September 24, 2006 12:00:00 AM", date "Saturday, August 12, 2006 12:00:00 AM"}

Hi, Adam. Yes. Any AppleScript sort routine that works by comparing similar items in a list should do the job.

Thanks, Nigel - it was my sorter that was screwing up. I wasn’t using an index list, I was removing each “found” low date from the original so the list that remained would be shorter. I thought that would be faster, but it wasn’t working.

This modified ASCII sorter does the job:

set theDates to {date "Thursday, June 1, 2006 12:00:00 AM", date "Tuesday, February 1, 2005 12:00:00 AM", date "Monday, January 1, 2007 12:00:00 AM", date "Monday, May 1, 2006 12:00:00 AM", date "Sunday, December 25, 2005 12:00:00 AM", date "Sunday, September 24, 2006 12:00:00 AM", date "Saturday, August 12, 2006 12:00:00 AM"}

set msg to ""
repeat with aDate in theDates -- original date list
	set msg to (msg & aDate as text) & return
end repeat
set msg to msg & return
set sortedDates to Sorter(theDates)
repeat with aDate in sortedDates -- sorted date list
	set msg to (msg & aDate as text) & return
end repeat
display dialog msg

to Sorter(my_list) -- a "standard" sorting package for lists
	set index_list to {}
	set sorted_list to {}
	set listCount to count my_list
	set lowDate to date "Monday, January 1, 1900 12:00:00 AM"
	repeat listCount times
		set the low_item to lowDate
		repeat with i from 1 to listCount
			if i is not in the index_list then
				set this_item to item i of my_list
				if the low_item is lowDate then
					set the low_item to this_item
					set the low_item_index to i
				else if this_item comes before the low_item then
					set the low_item to this_item
					set the low_item_index to i
				end if
			end if
		end repeat
		set the end of sorted_list to the low_item
		set the end of the index_list to the low_item_index
	end repeat
	return the sorted_list
end Sorter

Building two new lists (index_list and sorted_list) will have an impact on performance, Adam. Another way to approach this is to sort the existing list in place.

The following routine, for example, is about 130% faster here:

to sort_items from l
	tell (count l) to repeat with i from (it - 1) to 1 by -1
		set s to l's item i
		repeat with i from (i + 1) to it
			tell l's item i to if s > it then
				set l's item (i - 1) to it
			else
				set l's item (i - 1) to s
				exit repeat
			end if
		end repeat
		if it is i and s > l's end then set l's item it to s
	end repeat
end sort_items

set theDates to {date "Thursday, June 1, 2006 12:00:00", date "Tuesday, February 1, 2005 12:00:00", date "Monday, January 1, 2007 12:00:00", date "Monday, May 1, 2006 12:00:00", date "Sunday, December 25, 2005 12:00:00", date "Sunday, September 24, 2006 12:00:00", date "Saturday, August 12, 2006 12:00:00"}
sort_items from theDates

theDates --> {date "Tuesday, February 1, 2005 12:00:00", date "Sunday, December 25, 2005 12:00:00", date "Monday, May 1, 2006 12:00:00", date "Thursday, June 1, 2006 12:00:00", date "Saturday, August 12, 2006 12:00:00", date "Sunday, September 24, 2006 12:00:00", date "Monday, January 1, 2007 12:00:00"}

(As discussed previously, some form of referencing will help on substantially longer lists - but that’s not really a concern with a list of this size.)

Thanks, Kai. I’ve seen that sort before in a thread where sorting files by modification dates was the objective. It used an internal script object, and when I tried to modify it for a single list, I broke it, so I’m glad to see it in single list form.

The by mod_date handler, which was of your creation, went like this:

to sort_items(theList, sort_by) -- where theList was file names, and sort_by was a list of the corresponding modification dates.
	script o
		property tL : theList
		property sB : sort_by
	end script
	repeat with j from 2 to count o's tL
		set v to o's sB's item j
		set w to o's tL's item j
		repeat with j from j to 2 by -1
			set j to j - 1
			tell o's sB's item j to if v < it then
				set o's sB's item j to it
				set o's tL's item j to o's tL's item j
			else
				set o's sB's item j to v
				set o's tL's item j to w
				exit repeat
			end if
		end repeat
		if j is 2 and v < o's sB's item 1 then
			set o's sB's item 1 to v
			set o's tL's item 1 to w
		end if
	end repeat
end sort_items

Clearly the same roots.