Muddling with Weeks of Month

Suppose you have a series of meetings or get paid on the third (or any other) Thursday (or any other weekday) of the month. The script below gets me all the conceivable data I could want about the month a given date falls in, but I’m stuck on a neat way given such a date to get a sequence of future dates falling on the same weekday of the same week of succeeding months. I’ve poked around without finding one. I could brute force this with some repeat loops, but I’m guessing there’s a clever way.


set aDate to date "Monday, March 12, 2007 12:00:00 AM"
set WD to weekday of aDate --> Monday
-- calculate first day of month of aDate
-- subtract day of given date less one day
tell aDate to it - (day - 1) * days
set StartDate to result --> date "Thursday, March 1, 2007 12:00:00 AM"
-- get the weekday of first day
set WkDay_1 to weekday of StartDate --> Thursday
-- get the days in the month (DIM)
-- one-liner for DIM by Nigel Garvey
copy aDate to LD
set DIM to 32 - ((LD + (32 - (LD's day)) * days)'s day) --> 31
set LastDay to StartDate + ((DIM - 1) * days) --> date "Saturday, March 31, 2007 12:00:00 AM"
set LastWkDay to weekday of LastDay --> Saturday

Hi Adam,

unfortunately I have no solution for your actual problem,
but just for fun a summary of your script :wink:
(of course with help from one of Mr. G’s tremendous date math routines)

set aDate to date "Monday, March 12, 2007 12:00:00 AM"
set {StartDate, WkDay, LastDay, DIM, LastWkDay} to month_of(aDate)

on month_of(this_date)
	tell this_date to tell it + (32 - day) * days to tell it - day * days - time to return {it - (day - 1) * days, (it - (day - 1) * days)'s weekday, it, its day, its weekday}
end month_of

PS. I assume, you know Nigel’s DateTips 1.1

Sehr nett, Stefan, dank. :cool: I hadn’t made any attempt to shorten it because I just built it line-by-line. And yes, I’ve got a huge collection of Nigel’s and Kai’s time/date calculations and have spent many hours trying to unravel them.

Hi, Adam.

If you’re going for a sequence from the given date, it seems to be quite easy:

set aDate to date "Monday 12 March 2007 12:00:00"
set weekOfMonth to ((aDate's day) + 6) div 7
set dateSequence to {} -- or {aDate}

repeat 12 times
	set aDate to aDate + 5 * weeks
	if (((aDate's day) + 6) div 7 is not weekOfMonth) then set aDate to aDate - weeks
	set end of dateSequence to aDate
end repeat

dateSequence

If the base date’s in the first four weeks (ie. 28 days) of the month, the sequenced dates this produces are the same-numbered instance of that weekday in their own months. If the base date’s in the fifth week, the sequenced dates are the last instance of that weekday (which may be either the fourth or fifth) in those months.

I’m always deeply impressed by your date math skills, Nigel :slight_smile:

More to the point, I’m always deeply impressed by Nigel’s scripting skills, period. :cool:

Ditto Stefan’s remark, Nigel;

After a struggle, I understand what you have done, but simply can’t invent these things. There’s something general in this about counting cycles of anything which seems to be: Nth cycle, where N = (sample + (cycle_length - 1)) div cycle_length

e.g.

set myHours to 43
set HourHandCycles to (myHours + 11) div 12 --> 4
-- or
set lotsaHours to 456
set DaysPassed to (lotsaHours + 23) div 24 --> 20
set ApScDaysPassed to (lotsaHours * hours) div days --> 20
-- which take about the same time.

Hi, Adam.

Thanks to you, Stefan, and Kevin for your kind comments.

That’s right. It ensures that the cycle number changes on the first item of each cycle instead of on the last, which is what would happen if the sample number were simply divved by the cycle_length. It’s equivalent to N = (sample - 1) div cycle_length + 1.

set shortMonth to "Sep"
set monthNum to ((offset of shortMonth in "JanFebMarAprMayJunJulAugSepOctNovDec") + 2) div 3 --> 9
-- or:
set monthNum to ((offset of shortMonth in "JanFebMarAprMayJunJulAugSepOctNovDec") - 1) div 3 + 1 --> 9

Your last two examples .

. (for which the results are both actually 19!) aren’t equivalent. They give the same result because hour 456 is the last hour of day 19. (Use 455 or 457 instead and the difference becomes apparent.) The first result is the number of the day containing the hour; the second is the number of complete days at the completion of the hour. Or something… :rolleyes:

Thanks for pointing out the goof - further exploration shows that the discrepancy is most obvious here:


set lotsaHours to 23
set DaysPassed to (lotsaHours + 23) div 24 --> 1, i.e. in day 1
set ApScDaysPassed to (lotsaHours * hours) div days --> 0, i.e. not yet through day 1

Thanks for pointing that out.