This script reads out your daily agenda but ignores reoccurring events, please help. I am so new to AppleScript that I can take simple code and rearrange it for my needs, kind of. However, this code is a little complicated and I am having problems with it. My first problem was that I found this script on the internet but I didnât notice that it wasnât working properly until I had reoccurring events in my schedule. My second problem is that I canât find where I got the original code from. :rolleyes: I guess I should use that bookmarks button a little more.
When I run this script I find that it will say all of the events but it will not say the reoccurring events. I would also like this script to be able to read my todos to me but it does not. I realize that I am in a bit over my head but I appreciate any help.
set now to current date
set thisMorning to now - (time of now)
set thisEvening to thisMorning + 1 * days - 1
set foundOne to false
set det to ""
set today to now - (time of now)
set bname to ""
set dahead to 2
set dbefor to 30
tell application "iCal"
set foundOne to false
repeat with thisEvent in (every event of calendar "Birthdays")
tell thisEvent
set thedate to start date
if (month of thedate = month of now and day of thedate = day of now) then
set bname to summary
try
if not foundOne then
say "today is" & bname
set foundOne to true
else
say "today is also" & bname
end if
end try
end if
end tell
end repeat
set foundOne to false
say "Your agenda ..."
repeat with thisCalendar in calendars
repeat with thisEvent in ((every event of thisCalendar) whose ((start date ââ°ÂĽ thisMorning and start date ââ°Â¤ thisEvening) or (end date ââ°ÂĽ now and start date ââ°Â¤ thisMorning)))
set foundOne to true
tell thisEvent
set thedate to start date
set allday to allday event
try
if not allday then set theEventSummary to ("At " & time string of thedate & ", " & summary)
if allday then set theEventSummary to ("Today is " & summary)
set Esumm to summary
on error
set theEventSummary to " No summary - " & time string of thedate
set Esumm to ""
end try
try
set theEventDescription to description
set Edesc to description
log theEventDescription
on error
set theEventDescription to ""
set Edesc to ""
end try
end tell
say theEventSummary
say theEventDescription
end repeat
end repeat
set Esumm to ""
set Edesc to ""
repeat with calens in every calendar
if (count todos of calens) > 0 then
repeat with tasks in (todos of calens whose (due date > today - dbefor * days) and (due date ââ°Â¤ (today + dahead * days)))
try
completion date of tasks is missing value
on error
try
set foundOne to true
set det to det & "... The pending tasks are..." & return
set dd to due date of tasks
set d2 to month of dd & " " & day of dd
set dd to short date string of dd & " "
if character -2 of dd is ":" then set dd to dd
on error
set dd to tab
end try
try
set Esumm to det & summary of tasks & tab & "in " & d2 & tab & "..."
on error
set Esumm to ""
end try
try
set Edesc to description of tasks & ""
on error
set Edesc to ""
end try
try
set d3 to "" & d2 & ": " & summary of tasks
on error
set d3 to ""
end try
end try
end repeat
end if
end repeat
say Esumm
say Edesc
if foundOne then
say " and that's all."
end if
end tell
if not foundOne then say "There are no events scheduled"
end
The problem is this: iCal stores only one instance of recurrent events on the date of their creation (not necessarily on a day of the recurrence), and it generates all subsequent instances âon the flyâ each time you open a calendar. It does not do this when when a script retrieves events from iCal, however, so the script must do it.
The particulars of a set of repeating events are stored in the recurrence property of the original event as a semicolon-delimited Unicode text string. Like too many applications, however, there are not a fixed set of attributes with missing values for those not asserted. Instead, the string can take many forms using a labeling scheme to identify them (It would have been nicer for scripters if iCal had used a record here, but that would not have met the international iCalendar standard for calendar interoperability (RFC 2445). Compliant calendars use the ics extension for their data and certainly not all of them use records the way AppleScript does.
A storage scheme like iCalâs, which meets an international standard set up for easy parsing in a variety of environments, time zones and languages, means that a script to collect events must extract all of the events in a calendar rather than filter for those in a specified date range (events between two dates) because recurrences for which the first entry precedes the rangeâs beginning will not appear in the results of such a filtration - as mentioned, they are not computed for the AppleScript request. To show recurrences in a given date range where the first instance precedes the date range, your script must compute the dates on which they would fall in that range from the recurrence properties attached to the first (and only real) instance of the recurring event.
Not a trivial pursuit because parsing the recurrence string (with its very rich range of possibilites) is not trivial and a large number of handlers are required to do it.
Thanks for the description Adam, I had been wondering about this. Is there a generally used solution for âplease tell me all the events occuring at time xâ with AppleScript? I understand from what you said that to actually do it in AppleScript would require not only iterating through every event in every calendar but doing fairly complex math on the repeating ones, so presumably doing it in an interpreted language like thatâs not very feasable - is there perhaps a compiled solution that outputs text that we could grab into an AppleScript program to use, or similar?
My particular problem at the moment basically requires answering âWhat events are happening now?â, a slightly different problem from the OPâs.
Collecting recurrent events from a sweep through all of them doesnât take long â I do it every day with a âBirthdaysâ calendar, and a âMedicalâ calendar. The clue is to limit the types of recurrences you use so that parsing them is straight-forward.
Hereâs an example for my Birthdays calendar where they are all all day events and repeat in a simple way â once per year. If you respond with the types of recurrences you are using, perhaps I can help more.
-- 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
--quit
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 & "'"
else
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)
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
else
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
----
Iâve just posted a fairly comprehensive (and fairly long!) script to get the next recurrence date of an iCal event in Code Exchange, if itâs of any interest.