A handler that returns the calendar difference between two AppleScript dates in years, months, days, hours, minutes, and seconds. The result is in the form of a string, but this can be changed to a list or record if required. The convention used for the interpretation of a “month” is explained in the comments.
OS version: Any
-- calendarInterval() by Nigel Garvey, 29th/30th September 2004
-- Returns the calendar difference between two dates
-- in years, months, days, hours, minutes, seconds.
-- A "month" is understood as the interval between the same day and time in
-- adjacent calendar months. If the last complete "month" between two dates ends
-- in a calendar month that doesn't contain enough days for this interpretation,
-- the "month" is then taken to end on the last day of that calendar month.
on calendarInterval(earlierDate, laterDate)
if (earlierDate comes after laterDate) then
set {laterDate, earlierDate} to {earlierDate, laterDate}
set sign to "-"
else
set sign to ""
end if
-- Subtract the year, day, time, and month numbers individually.
set {y, d, t} to {(laterDate's year) - (earlierDate's year), (laterDate's day) - (earlierDate's day), (laterDate's time) - (earlierDate's time)}
copy {laterDate, earlierDate} to {b, c}
set {b's month, c's month} to {January, January}
set m to (b - 2500000 - laterDate) div -2500000 - (c - 2500000 - earlierDate) div -2500000
-- Perform any necessary borrows.
if (t < 0) then set {d, t} to {d - 1, t + days} -- borrow a day, add to time.
if (d < 0) then -- borrow the calendar month before laterDate, add to days.
set m to m - 1
set daysInMonth to (laterDate - (laterDate's day) * days)'s day
-- If the month has fewer days than earlierDate's day number, use the
-- earlierDate number instead. This is equivalent to treating the last day
-- of the calendar month as the last day of the "months" period. Trust me. :-)
if (daysInMonth < earlierDate's day) then set daysInMonth to earlierDate's day
set d to d + daysInMonth
end if
if (m < 0) then set {y, m} to {y - 1, m + 12} -- borrow a year, add to months.
-- Extract the indvidual time units.
set {h, min, s} to {t div hours, t mod hours div minutes, t mod minutes}
return sign & y & " yr " & m & " mth " & d & " dy " & h & " hr " & min & " min " & s & " sec"
end calendarInterval
-- Demo:
calendarInterval(date "Saturday, 5 June 1999 00:12:30", date "Friday, 4 June 2004 00:12:30")
--> "4 yr 11 mth 30 dy 0 hr 0 min 0 sec"