Problems with iCal event time and applescript...

I’ve read the various forum postings on this topic, and tried to comprehend and cannibalise, but I’ve hit a brick wall and am throwing myself on this community for salvation!

I’m trying to create a script which makes a similar function to ‘Laytr’, where message is sent back to you at a date on your choosing when you’ll need to be reminded of it. The script takes a messages in mail and makes an Ical event of the same, with an alarm for the date chosen by the user.

I’ve got the creation of the event ok but it’s the setting of the date for the mail alarm that’s the problem. Here’s my code:

property toDoCompletionDate : ""
set newline to ASCII character 10
gettime()

tell application "Mail"
	using terms from application "Mail"
		set selectedMails to selection
		repeat with eachMessage in selectedMails
			
			-- creates the event and alarm
			
			tell application "iCal" to tell calendar "Calendar"
				set theEvent to make new event at end with properties {description:message_body, summary:thetitle, start date:toDoCompletionDate, end date:toDoCompletionDate, allday event:true}
				tell theEvent to make new mail alarm at end with properties {trigger date:toDoCompletionDate}
			end tell
			
			-- moves the original mail message to a holding folder
			
			set mailbox of eachMessage to mailbox "[Google Mail]/ Projects/Remind Later" of account "Personal"
			
		end repeat
	end using terms from
end tell

on gettime()
	
	-- get some details about the current date for comparing the new date
	
	set theDay to day of (current date) as integer
	set theMonth to month of (current date) as integer
	set theYear to year of (current date) as integer
	
	-- get the current date and month to be default text
	
	set thedaytext to theDay as text
	set thedaymonth to theMonth as text
	set answery to thedaytext & "/" & theMonth
	set theDefaultDate to text returned of (display dialog "Enter the date (DD/MM)" buttons {"Cancel", "Set Date"} default button "Set Date" default answer answery) as string
	
	-- compare whether the event is ahead of or behind the current date, and if the latter, add one year to the date
	
	set newday to text 1 thru 2 of theDefaultDate
	try
		set newmonth to text 4 thru 5 of theDefaultDate as integer
	on error
		set newmonth to text 4 of theDefaultDate as integer
	end try
	if theMonth is greater than newmonth then set theYear to theYear + 1
	if theMonth is equal to newmonth then if theDay is greater than newday then set theYear to theYear + 1
	set theDefaultDate to theDefaultDate & "/" & theYear
	
	-- convert from DD/MM/YY into a date format
	
	my setDate(theDefaultDate)
	
	-- change the time from midnight to 6.30am for the mail alarm to be sent
	
	set toDoCompletionDate to date string of date theDefaultDate & " 06:30:00"
	
	return date toDoCompletionDate
end gettime

-- this borrowed from a previous forum post.

on setDate(theDateStr)
	set {R, TID} to {false, text item delimiters}
	repeat with i in {"/", "-", " "}
		set text item delimiters to i
		set {x, text item delimiters} to {every text item in theDateStr, TID}
		if (count of x) ≥ 3 then
			set {R, R's year} to {date theDateStr, item 3 of x}
			exit repeat
		end if
	end repeat
	return R
end setDate


Whenever I run this, I get this error (the date is the one I happened to enter, today:

error "iCal got an error: Can't make \"Monday, 26 September 2011 06:30:00\" into type date." number -1700 from "Monday, 26 September 2011 06:30:00" to date

All help gratefully received!

Model: Macbook 13"
AppleScript: 2.2
Browser: Safari 534.48.3
Operating System: Mac OS X (10.7)

Variable newline is never used.

Variables message_body and thetitle are never set.
As message_body is the 1st one encountered the script errors on it not being defined.

I do not understand how it gets to that date error; building toDoCompletionDate correctly yields a date object (in my Dutch system too), so it should not error there.

Did you leave out something?

There’s more code which I use to create an event in Things (that’s where variable newline gets used); however, when I run the code as pasted, I get the same error. I can paste the entire script, but it does lengthen the post somewhat, which seemed to be unnecessary and potentially annoying. FWIW, whole code here:

property toDoCompletionDate : ""
set newline to ASCII character 10
gettime()

tell application "Mail"
	using terms from application "Mail"
		set selectedMails to selection
		repeat with eachMessage in selectedMails
			set read status of eachMessage to true
			set the selected_message to item 1 of eachMessage
			set message_id to urlencode(the message id of eachMessage) of me
			set message_body to content of eachMessage
			set thetitle to subject of the eachMessage
			set theSubject to the subject of the eachMessage & " (From " & the sender of the eachMessage & ")"
			set message_url to "[url=message:%3C" & (message_id) & "%3E]" & theSubject & "[/url]"
			set theBody to "Link to Message: " & message_url & newline & newline & message_body
			
			tell application "Things" to set newToDo to make new to do with properties {name:theSubject, notes:theBody, tag names:"Remind"} at beginning of list "Someday"
			tell application "iCal" to tell calendar "Calendar"
				set theEvent to make new event at end with properties {description:message_body, summary:thetitle, start date:toDoCompletionDate, end date:toDoCompletionDate, allday event:true}
				tell theEvent to make new mail alarm at end with properties {trigger date:toDoCompletionDate}
			end tell
			set mailbox of eachMessage to mailbox "[Google Mail]/ Projects/Remind Later" of account "Personal"
			
		end repeat
	end using terms from
end tell



on gettime()
	set theDay to day of (current date) as integer
	set theMonth to month of (current date) as integer
	set theYear to year of (current date) as integer
	set thedaytext to theDay as text
	set thedaymonth to theMonth as text
	set answery to thedaytext & "/" & theMonth
	set theDefaultDate to text returned of (display dialog "Enter the date (DD/MM)" buttons {"Cancel", "Set Date"} default button "Set Date" default answer answery) as string
	set newday to text 1 thru 2 of theDefaultDate
	try
		set newmonth to text 4 thru 5 of theDefaultDate as integer
	on error
		set newmonth to text 4 of theDefaultDate as integer
	end try
	if theMonth is greater than newmonth then set theYear to theYear + 1
	if theMonth is equal to newmonth then if theDay is greater than newday then set theYear to theYear + 1
	
	set theDefaultDate to theDefaultDate & "/" & theYear
	my setDate(theDefaultDate)
	set toDoCompletionDate to date string of date theDefaultDate & " 06:30:00"
	return date toDoCompletionDate
end gettime

on setDate(theDateStr)
	set {R, TID} to {false, text item delimiters}
	repeat with i in {"/", "-", " "}
		set text item delimiters to i
		set {x, text item delimiters} to {every text item in theDateStr, TID}
		if (count of x) ≥ 3 then
			set {R, R's year} to {date theDateStr, item 3 of x}
			exit repeat
		end if
	end repeat
	return R
end setDate

on urlencode(theText)
	set theTextEnc to ""
	repeat with eachChar in characters of theText
		set useChar to eachChar
		set eachCharNum to ASCII number of eachChar
		if eachCharNum = 32 then
			set useChar to "+"
		else if (eachCharNum ≠ 42) and (eachCharNum ≠ 95) and (eachCharNum < 45 or eachCharNum > 46) and (eachCharNum < 48 or eachCharNum > 57) and (eachCharNum < 65 or eachCharNum > 90) and (eachCharNum < 97 or eachCharNum > 122) then
			set firstDig to round (eachCharNum / 16) rounding down
			set secondDig to eachCharNum mod 16
			if firstDig > 9 then
				set aNum to firstDig + 55
				set firstDig to ASCII character aNum
			end if
			if secondDig > 9 then
				set aNum to secondDig + 55
				set secondDig to ASCII character aNum
			end if
			set numHex to ("%" & (firstDig as string) & (secondDig as string)) as string
			set useChar to numHex
		end if
		set theTextEnc to theTextEnc & useChar as string
	end repeat
	return theTextEnc
end urlencode


Well, it looks like my statement about toDoCompletionDate being a good date object was wrong - it’s actually text, looking like a date object.
This makes it work:

.
.
gettime()
set toDoCompletionDate to date toDoCompletionDate

I am giving you big sloppy non-romantic kisses of gratitude. Thanks so much!

Hmm. Flushed with having made the darned script work, I ported the key lines of code into this script below; I’m now getting the same error as above in this new script. I originally tried having it call a subroutine get time(), but no dice - wouldn’t allow it, so went instead for the below. Can anyone see what’s wrong?

set newline to ASCII character 10

tell application "Mail"
	using terms from application "Mail"
		set selectedMails to selection
		repeat with eachMessage in selectedMails
			set read status of eachMessage to true
			
			-- gets user input for the date
			
			if button returned of (display dialog "Do you want to add a date?" buttons {"Yes", "No"} default button "yes") is "Yes" then
				set theDay to day of (current date) as integer
				set theMonth to month of (current date) as integer
				set theYear to year of (current date) as integer
				set thedaytext to theDay as rich text
				set thedaymonth to theMonth as rich text
				set answery to thedaytext & "/" & theMonth
				set theDefaultDate to text returned of (display dialog "Enter the date (DD/MM)" buttons {"Cancel", "Set Date"} default button "Set Date" default answer answery) as string
				set newday to rich text 1 thru 2 of theDefaultDate
				try
					set newmonth to rich text 4 thru 5 of theDefaultDate as integer
				on error
					set newmonth to rich text 4 of theDefaultDate as integer
				end try
				if theMonth is greater than newmonth then set theYear to theYear + 1
				if theMonth is equal to newmonth then if theDay is greater than newday then set theYear to theYear + 1
				
				set theDefaultDate to theDefaultDate & "/" & theYear
				my setDate(theDefaultDate)
				set toDoCompletionDate to date theDefaultDate
				
				-- or else leaves this variable blank
				
			else
				set toDoCompletionDate to ""
			end if
			
			-- gets mail-related info for the Things todo
			
			set the selected_message to item 1 of eachMessage
			set message_id to urlencode(the message id of eachMessage) of me
			set message_body to content of eachMessage
			set theSubject to the subject of the eachMessage & " (From " & the sender of the eachMessage & ")"
			set message_url to "[url=message:%3C" & (message_id) & "%3E]" & theSubject & "[/url]"
			set theBody to "Link to Message: " & message_url & newline & newline & message_body
			
			-- gets user input for which list/project/tag to file the to-do under (and add new projects or tags) then adds the to-do
			
			tell application "Things" to set all_tags to name of every tag & "New Tag."
			set default_list to ""
			set default_project to ""
			set default_tag to ""
			activate
			tell application "Things" to set all_projects to name of every project & "New Project..."
			activate
			
			set listname to (choose from list {"Projects", "Inbox", "Today", "Scheduled", "Someday"} with prompt "Select the Project for this Task:" OK button name "Add" default items "Inbox" without multiple selections allowed and empty selection allowed) as Unicode text
			if listname is "Projects" then
				set projecty to (choose from list all_projects with prompt "Select the Project for this Task:" OK button name "Add Project" default items {default_project} without multiple selections allowed and empty selection allowed) as Unicode text
				if projecty is "New Project." then
					set projecty to text returned of (display dialog "What is the new project?" default answer "")
					tell application "Things" to set newProject to make new project with properties {name:projecty} at end of list "Projects"
				end if
				set taggy to (choose from list all_tags with prompt "Select the Tags for this Task:" OK button name "Tag" default items {default_tag} with multiple selections allowed and empty selection allowed) as Unicode text
				if taggy is "New Tag." then
					set taggy to text returned of (display dialog "What is the new tag?" default answer "")
					tell application "Things" to set newTag to make new tag with properties {name:taggy}
				end if
				
				if toDoCompletionDate is "" then
					tell application "Things" to set newToDo to make new to do with properties {name:theSubject, notes:theBody, tag names:taggy} at beginning of project projecty
				else
					tell application "Things" to set newToDo to make new to do with properties {name:theSubject, notes:theBody, tag names:taggy, due date:toDoCompletionDate} at beginning of project projecty
				end if
			else
				set taggy to (choose from list all_tags with prompt "Select the Tags for this Task:" OK button name "Tag" default items {default_tag} with multiple selections allowed and empty selection allowed) as Unicode text
				if taggy is "New Tag." then
					set taggy to text returned of (display dialog "What is the new tag?" default answer "")
					tell application "Things" to set newTag to make new tag with properties {name:taggy}
				end if
				if toDoCompletionDate is "" then
					tell application "Things" to set newToDo to make new to do with properties {name:theSubject, notes:theBody, tag names:taggy} at beginning of list listname
				else
					tell application "Things" to set newToDo to make new to do with properties {name:theSubject, notes:theBody, tag names:taggy, due date:toDoCompletionDate} at beginning of list listname
				end if
				
			end if
		end repeat
	end using terms from
end tell

-- just for doing some jiggery pokery to the Mail URL

on urlencode(theText)
	set theTextEnc to ""
	repeat with eachChar in characters of theText
		set useChar to eachChar
		set eachCharNum to ASCII number of eachChar
		if eachCharNum = 32 then
			set useChar to "+"
		else if (eachCharNum ≠ 42) and (eachCharNum ≠ 95) and (eachCharNum < 45 or eachCharNum > 46) and (eachCharNum < 48 or eachCharNum > 57) and (eachCharNum < 65 or eachCharNum > 90) and (eachCharNum < 97 or eachCharNum > 122) then
			set firstDig to round (eachCharNum / 16) rounding down
			set secondDig to eachCharNum mod 16
			if firstDig > 9 then
				set aNum to firstDig + 55
				set firstDig to ASCII character aNum
			end if
			if secondDig > 9 then
				set aNum to secondDig + 55
				set secondDig to ASCII character aNum
			end if
			set numHex to ("%" & (firstDig as string) & (secondDig as string)) as string
			set useChar to numHex
		end if
		set theTextEnc to theTextEnc & useChar as string
	end repeat
	return theTextEnc
end urlencode

-- Converts output of date dialog box

on setDate(theDateStr)
	set {R, TID} to {false, text item delimiters}
	repeat with i in {"/", "-", " "}
		set text item delimiters to i
		set {x, text item delimiters} to {every text item in theDateStr, TID}
		if (count of x) ≥ 3 then
			set {R, R's year} to {date theDateStr, item 3 of x}
			exit repeat
		end if
	end repeat
	return R
end setDate

Some things you may or may not be aware of.

First, when you called the subroutine from within the tell Mail block it should be my gettime(), not gettime() (me being the script).

Second, do you know about the log command? Insert something like this at various places in the script:

log {class of toDoCompletionDate, toDoCompletionDate}

Run the script in the Editor, and you will see what it does in the panel at the bottom (might need to click ‘events’ button). The output of the log command is shown with comment layout. Obviously, toDoCompletionDate’s class should be ‘date’.

And

tell application "Mail"
	using terms from application "Mail"
		-- lots of code here
	end using terms from
end tell

I think the using terms clause is redundant. The script is already talking to Mail.

Thanks for this Alastor!