Thursday, September 2, 2010

#1 2007-05-14 05:27:07 pm

Adam Bell
Administrator
From: Nova Scotia, Canada
Registered: 2005-10-04
Posts: 4255

A date manipulation problem (monthly events)

I've recently put this together (borrowing heavily from Nigel Garvey's DateTips in ScriptBuilders.net) to calculate the dates of monthly events that always occur on the same day of the week approximately one month apart. Seems a little coarse to me, though it works. Any suggestions for streamlining it?

Applescript:

set tDates to {}
set Now to (current date) -- or any date given.
set WD to weekday of Now
repeat with k from 1 to 5
   set newDate to addMonths(Now, k)
   set end of tDates to getNearestWkDay(newDate, WD)
end repeat

to addMonths(oldDate, m) -- returns a date
   -- adapted from a script by Nigel Garvey (N.G.)
   copy oldDate to newDate
   -- Convert the month-offset parameter to years and months
   set {y, m} to {m div 12, m mod 12}
   -- Add the year offset into the new date's year
   set newDate's year to (newDate's year) + y
   -- Add the odd months (at 32 days per month) and set the day
   if m is not 0 then tell newDate to set {day, day} to {32 * m, day}
   -- If the day's now wrong, it doesn't exist in the target month
   -- Subtract the overflow into the following month to return to the last day of the target month
   if newDate's day is not oldDate's day then set newDate to newDate - (newDate's day) * days
   return newDate
end addMonths

to getNearestWkDay(aDate, tWeekDay)
   -- get the day of the date given (used to check later)
   set tDay to day of aDate
   -- get the days in the month so we won't run over to the nearest day
   set DaysInMo to 32 - ((aDate + (32 - (aDate's day)) * days)'s day) -- N.G. again
   set OffBy to (tWeekDay as number) - (weekday of aDate)
   -- go back or forward for closest day of the week
   if OffBy < -3 then
       set OffBy to OffBy + 7
   else if OffBy > 3 then
       set OffBy to OffBy - 7
   end if
   -- check that offset doesn't move into another month
   -- don't jump forward into next month to nearest weekday
   if tDay + OffBy > DaysInMo then set OffBy to OffBy - 7
   -- don't jump backward into former month to nearest weekday
   if tDay + OffBy < 1 then set OffBy to OffBy + 7
   set newDate to aDate + OffBy * days
   return newDate
end getNearestWkDay


Scripts are tested on a PowerMac dual-core G5/2.3 running OS X 10.5.8 or MacBook Pro Intel Core 2 Duo running OS X 10.6.4

Offline

 

#2 2007-05-14 06:44:25 pm

mcgrailm
Member
Registered: 2006-11-24
Posts: 506

Re: A date manipulation problem (monthly events)

are you trying to get the first (Friday) of the month kind of thing  ?

mm

Offline

 

#3 2007-05-14 08:05:22 pm

Nigel Garvey
Moderator
From: Warwickshire, England
Registered: 2002-11-19
Posts: 2014

Re: A date manipulation problem (monthly events)

Hi, Adam.

Here's a very slightly more economical version. I think it's OK….

Applescript:

set tDates to {}
set Now to (current date) -- or any date given.
repeat with k from 1 to 12
   set newDate to addMonths(Now, k)
   set end of tDates to getNearestWkDay(newDate, Now)
end repeat
tDates

to addMonths(oldDate, m) -- returns a date
   -- adapted from a script by Nigel Garvey (N.G.)
   copy oldDate to newDate
   -- Convert the month-offset parameter to years and months
   set {y, m} to {m div 12, m mod 12}
   -- Add the year offset into the new date's year
   set newDate's year to (newDate's year) + y
   -- Add the odd months (at 32 days per month) and set the day
   if m is not 0 then tell newDate to set {day, day} to {32 * m, day}
   -- If the day's now wrong, it doesn't exist in the target month
   -- Subtract the overflow into the following month to return to the last day of the target month
   if newDate's day is not oldDate's day then set newDate to newDate - (newDate's day) * days
   return newDate
end addMonths

on getNearestWkDay(aDate, refDate)
   -- Get the nearest date to aDate that has the same weekday as refDate.
   set newDate to refDate + quantise(aDate - refDate, weeks)
   -- If it's not in the same month, get the second-nearest such date!
   if (newDate's month is aDate's month) then
       return newDate
   else if (newDate comes before aDate) then
       return newDate + weeks
   else
       return newDate - weeks
   end if
end getNearestWkDay

(* Round to nearest multiple of q (q/2 away from zero) *)
-- from aRounderRound by NG, ScriptBuilders.
on quantise(n, q)
   (n * 2 div q - n div q) * q
end quantise


NG

Offline

 

#4 2007-05-15 09:38:40 am

Adam Bell
Administrator
From: Nova Scotia, Canada
Registered: 2005-10-04
Posts: 4255

Re: A date manipulation problem (monthly events)

Very much better Mr. G! smile It was indeed all that to-ing and fro-ing to test for the nearest correct weekday without falling back into or leaping forward into a different month that needed some punch. Quantise [sic] with your simpler test following does it [sic, because I would have called it quantize]. Now, I've only to sort out what quantise is actually doing. roll I'll grab aRounderRound which I had not seen before (perceived it to be pre-X only) and have a squint at it. [Edit: I've altered the system designation on aRounderRound to 9/X from 9)

Thanks,

Adam


Scripts are tested on a PowerMac dual-core G5/2.3 running OS X 10.5.8 or MacBook Pro Intel Core 2 Duo running OS X 10.6.4

Offline

 

Board footer

Powered by FluxBB

[ Generated in 0.213 seconds, 8 queries executed ]

RSS (new topics) RSS (active topics)