How can I get the number of weekdays (Monday to Friday) in a select month?

The month has to be in the context of a year, as in a date object.

Brute-force method:

```
set dateWithMonth to (current date)
set thisMonth to dateWithMonth's month
set nWeekdays to 0
repeat with i from 1 to 31
set dateWithMonth's day to i
if (dateWithMonth's month is not thisMonth) then exit repeat
set w to dateWithMonth's weekday
if not ((w is Saturday) or (w is Sunday)) then set nWeekdays to nWeekdays + 1
end repeat
return nWeekdays
```

I’ll try to think of a date-math version.

Excellent Thankyou

much more code but probably faster (however I’m sure Nigel will provide the ultimate solution )

```
set numberOfWeekdays to numberOfWeekdaysInCurrentMonthForDate(current date)
on numberOfWeekdaysInCurrentMonthForDate(aDate)
-- calculate number of days of aDate
set numberOfDaysInCurrentMonth to 32 - ((aDate + (32 - (aDate's day)) * days)'s day)
-- calculate the weekday of 1st day of current month
tell (aDate - (((aDate's day) - 1) * days)) to set weekDayOfFirstOfMonth to its weekday
-- each month has always at least 8 weekend days
set defaultNumberOfWorkingDays to numberOfDaysInCurrentMonth - 8
if weekDayOfFirstOfMonth is Sunday then
-- + 1 weekend day if numberOfDaysInCurrentMonth > 28
return defaultNumberOfWorkingDays - ((numberOfDaysInCurrentMonth > 28) as integer)
else if weekDayOfFirstOfMonth is Thursday then
-- + 1 weekend day if numberOfDaysInCurrentMonth = 31
return defaultNumberOfWorkingDays - ((numberOfDaysInCurrentMonth = 31) as integer)
else if weekDayOfFirstOfMonth is Friday then
-- + 1 weekend day if numberOfDaysInCurrentMonth = 30
-- + 2 weekend days if numberOfDaysInCurrentMonth = 31
set additionWeekendDays to numberOfDaysInCurrentMonth - 29
if additionWeekendDays < 1 then
return defaultNumberOfWorkingDays
else
return defaultNumberOfWorkingDays - additionWeekendDays
end if
else if weekDayOfFirstOfMonth is Saturday then
-- + 1 weekend day if numberOfDaysInCurrentMonth = 29
-- + 2 weekend days if numberOfDaysInCurrentMonth > 29
if numberOfDaysInCurrentMonth < 29 then
return defaultNumberOfWorkingDays
else if numberOfDaysInCurrentMonth = 29 then
return defaultNumberOfWorkingDays - 1
else
return defaultNumberOfWorkingDays - 2
end if
else
return defaultNumberOfWorkingDays
end if
end numberOfWeekdaysInCurrentMonthForDate
```

Hello.

Here is my take, I use the fact that there is 20 days in a month, whatever day the month starts with.

if it is 29 days, and starts with a saturday, then the daynumber is the same as above.

If the week starts with a thursday, and there is 31 days in the month, then I have an extranous saturday, so I must substract 9 weekend-days from the number of days in the month.

If the week starts with a friday and there is 31 days I have two extra weekend - days that must be subtracted from the number of days of the month, 1 less to subtract if the number of days is 30.

Else if it starts with saturday, or sunday, I add 2 resepctively 1 to the 8 weekend days, which I then subtract from the total number of days in the month.

```
set numberOfWeekdays to numberOfWorkingdaysInMonthFor(current date)
on numberOfWorkingdaysInMonthFor(aDate)
-- calculate number of days of aDate
set numberOfDaysInCurrentMonth to 32 - ((aDate + (32 - (aDate's day)) * days)'s day)
if numberOfDaysInCurrentMonth = 28 then return 20
-- calculate the weekday of 1st day of current month
tell (aDate - (((aDate's day) - 1) * days)) to set weekDayOfFirstOfMonth to its weekday
if weekDayOfFirstOfMonth is Thursday then
if numberOfDaysInCurrentMonth = 31 then return numberOfDaysInCurrentMonth - 9
return numberOfDaysInCurrentMonth - 8
end if
if weekDayOfFirstOfMonth is Friday then
if numberOfDaysInCurrentMonth = 31 then return numberOfDaysInCurrentMonth - 10
if numberOfDaysInCurrentMonth = 30 then return numberOfDaysInCurrentMonth - 9
end if
if weekDayOfFirstOfMonth is Saturday then
if numberOfDaysInCurrentMonth = 29 then
return numberOfDaysInCurrentMonth - 9
else
return numberOfDaysInCurrentMonth - 10
end if
end if
if weekDayOfFirstOfMonth is Sunday then return numberOfDaysInCurrentMonth - 9
return numberOfDaysInCurrentMonth - 8
end numberOfWorkingdaysInMonthFor
```

Edit

After fixing this, I’ll have to go back and see how much this differs from Stefan’s solution.

I didn’t take height for the early week-ending or start a thursday/friday, with a daynumber of 30/31 the first time around.

nice one, but it doesn’t consider the thursday case with 31 days which should result 22

Hello Stefan.

It wouldn’t look good without the way of calculating number of days in a month, which I snagged from you (together with most of the code).

I have fixed the “fluctuating week-ending”, it should be all right now.

you gave me the idea to distinguish the days of the months instead of the weekdays

```
set numberOfWeekdays to numberOfWeekdaysInCurrentMonthForDate(current date)
on numberOfWeekdaysInCurrentMonthForDate(aDate)
-- calculate number of days of aDate
set numberOfDaysInCurrentMonth to 32 - ((aDate + (32 - (aDate's day)) * days)'s day)
-- calculate the weekday of 1st day of current month
tell (aDate - (((aDate's day) - 1) * days)) to set weekDayOfFirstOfMonth to its weekday
-- each month has always at least 8 weekend days
set defaultNumberOfWorkingDays to numberOfDaysInCurrentMonth - 8
if numberOfDaysInCurrentMonth = 28 then
return defaultNumberOfWorkingDays
else if numberOfDaysInCurrentMonth = 29 then
return defaultNumberOfWorkingDays - ((weekDayOfFirstOfMonth is Sunday or weekDayOfFirstOfMonth is Saturday) as integer)
else if numberOfDaysInCurrentMonth = 30 then
if (weekDayOfFirstOfMonth is Friday) then
return defaultNumberOfWorkingDays - 1
else if (weekDayOfFirstOfMonth is Saturday) then
return defaultNumberOfWorkingDays - 2
end if
else
if (weekDayOfFirstOfMonth is Thursday) then
return defaultNumberOfWorkingDays - 1
else if (weekDayOfFirstOfMonth is Friday) then
return defaultNumberOfWorkingDays - 2
end if
end if
return defaultNumberOfWorkingDays
end numberOfWeekdaysInCurrentMonthForDate
```

or

```
set numberOfWeekdays to numberOfWeekdaysInCurrentMonthForDate(current date)
on numberOfWeekdaysInCurrentMonthForDate(aDate)
-- calculate number of days of aDate
set numberOfDaysInCurrentMonth to 32 - ((aDate + (32 - (aDate's day)) * days)'s day)
-- calculate the weekday of 1st day of current month
tell (aDate - (((aDate's day) - 1) * days)) to set weekDayOfFirstOfMonth to its weekday
-- each month has always at least 8 weekend days
set defaultNumberOfWorkingDays to numberOfDaysInCurrentMonth - 8
if numberOfDaysInCurrentMonth = 28 then
return defaultNumberOfWorkingDays
else if numberOfDaysInCurrentMonth = 29 then
return defaultNumberOfWorkingDays - ((weekDayOfFirstOfMonth is Sunday or weekDayOfFirstOfMonth is Saturday) as integer)
else if (numberOfDaysInCurrentMonth = 30 and weekDayOfFirstOfMonth is Friday) or (numberOfDaysInCurrentMonth = 31 and weekDayOfFirstOfMonth is Thursday) then
return defaultNumberOfWorkingDays - 1
else if (numberOfDaysInCurrentMonth = 30 and weekDayOfFirstOfMonth is Saturday) or (numberOfDaysInCurrentMonth = 31 and weekDayOfFirstOfMonth is Friday) then
return defaultNumberOfWorkingDays - 2
else
return defaultNumberOfWorkingDays
end if
end numberOfWeekdaysInCurrentMonthForDate
```

That is even better Stefan.

The only thing amiss here, is the subtraction of hollidays that fall upon workingdays. But that I must postpone, too much to read. Maybe the computer industry is a conspiracy instigated by opticans?

Hi.

This is the best I’ve got so far. It seems to be essentially the same as Stefan’s except that it uses the weekday of the last day in the month, since we’ve already calculated that date. I’d like to do something clever with the weekday numbers, but I’m in the middle of a situation at home at the moment.

```
set dateWithMonth to (current date)
tell dateWithMonth to tell it + (32 - (its day)) * days to set {day:monthLength, weekday:endWeekday} to it - (its day) * days
set nWeekdays to monthLength - 8
if (monthLength is 29) and (endWeekday is Sunday) then
set nWeekdays to nWeekdays - 1
else if (monthLength is 30) then
if (endWeekday is Sunday) then
set nWeekdays to nWeekdays - 2
else if (endWeekday is Monday) or (endWeekday is Saturday) then
set nWeekdays to nWeekdays - 1
end if
else if (monthLength is 31) then
if (endWeekday is Sunday) or (endWeekday is Monday) then
set nWeekdays to nWeekdays - 2
else if (endWeekday is Tuesday) or (endWeekday is Saturday) then
set nWeekdays to nWeekdays - 1
end if
end if
return nWeekdays
```

Hello.

I was actually thinking of something like using numbers before you mentioned it, but too lazy.

I hope everything is ok.

This is my version, which I have hopefully checked thoroughly enough! I use the day numbers, but skips the sunday, as it complicates the whole algortihm, (as do saturday).

I add the day-number of the first day of the month to the number of days of the month, if the number is greater than 35 I add the difference to the 8 weekend-days, but if the difference is 3 then I subtract one (month starts with a saturday).

```
set numberOfWeekdays to numberOfWorkingdaysInMonthFor(current date)
on numberOfWorkingdaysInMonthFor(aDate)
-- calculate number of days of aDate
set numberOfDaysInCurrentMonth to 32 - ((aDate + (32 - (aDate's day)) * days)'s day)
if numberOfDaysInCurrentMonth = 28 then
set workingdays to 20
else
tell (aDate - (((aDate's day) - 1) * days)) to set weekDayOfFirstOfMonth to its weekday
if weekDayOfFirstOfMonth is Sunday then
set workingdays to numberOfDaysInCurrentMonth - 9
else
-- thursday friday and saturday, will cause a 5th weekend if the daynumber of the month
-- is from 29 to 31 days, the case with sunday is handled above.
set lap to ((weekDayOfFirstOfMonth as integer) + numberOfDaysInCurrentMonth) - 35
if lap â‰¥ 1 and lap â‰¤ 2 then
else if lap = 3 then
-- Justifies the calulation, as it may come out wrongly for saturday
-- since a weekend consists of 2 days at most.
set lap to 2
else
set lap to 0 -- No adjustment needed.
end if
set workingdays to numberOfDaysInCurrentMonth - (8 + lap)
end if
end if
return workingdays
end numberOfWorkingdaysInMonthFor
```

```
workdaysInMonth(current date)
on workdaysInMonth(dateWithMonth)
tell dateWithMonth to tell it + (32 - (its day)) * days to set {day:monthLength, weekday:endWeekday} to it - (its day) * days
if (monthLength is 28) then return 20
return monthLength - 8 - ((endWeekday < monthLength - 28) as integer) - ((endWeekday mod 7 < monthLength - 27) as integer)
end workdaysInMonth
```

Nigel’s solution is what I had in mind. There are always 28 days (4 weeks) in a month and there is only an overlap of 1, 2 or 3 days. You only have to consider if that overlap is in the weekend or not. Kudos to Nigel (again)!

brilliant

I can just say as Stefan: Absolutely Brilliant Nigel.

Thanks. But it was only a matter of compressing the logic from my earlier script. Even less efficiently, it could be rendered thus:

```
workdaysInMonth(current date)
on workdaysInMonth(dateWithMonth)
tell dateWithMonth + (32 - (dateWithMonth's day)) * days to tell it - day * days to return day - 8 - (((its weekday) < day - 28) as integer) - (((its weekday) mod 7 < day - 27) as integer) * ((day > 28) as integer)
end workdaysInMonth
```