
Guides
Part of Workday counts for a month: why length and starting weekday decide the total
Working days per month formula: test vectors and checks for your code
Test a working days per month formula before you trust it: edge spans, a month-by-month 2027 sum, a day-by-day sweep and the off-by-one bugs.
Choose the branch that matches the input your code receives. The target here is a weekday total, not a full closure-aware workday count: the fast check uses whole weeks, then inspects the leftover days. A test suite should make the counting convention visible before it checks the arithmetic.
If the input is one complete calendar month
For one calendar month, start at 20 and inspect only dates after day 28. Those dates repeat the weekday names at the start of the month, adding one for each Monday-to-Friday occurrence and zero for Saturday or Sunday; consequently, every 28-day February returns 20.
For any consecutive span, express its length n as 7w + r, where r is from 0 through 6. Each complete week contributes five weekdays, then the r leftover days contribute according to the span's starting weekday. This is the same modular weekday arithmetic whether the span is a month or not.
Deriving the working-day formula
- n = 7w + r, r between 0 and 6
- w whole weeks contribute 5w weekdays
- Only r leftover days depend on start
- Month: w = 4, r = n - 28
- Rule: 20 + weekdays in first n-28 days
When mapping a calendar date to a weekday input, keep date representation separate from the count. The ISO date and time format and the US Naval Observatory Julian date page are references for date notation, not workday rules; the function still needs a starting weekday and a length.
- Rule of thumb: Use the 20-day base only when the input is a full month.
If a boundary vector fails
If a result fails a boundary vector, investigate inclusivity or the remainder before changing the formula. Use Saturday and Sunday as rest days, exclude no closure dates, and count both endpoints in every row below. The expected values are hand-checkable, and each row isolates a likely boundary case.
| Span | Expect | What it catches |
|---|---|---|
| 1 to 31 March 2027 | 23 | The ordinary case |
| 1 to 28 February 2027 | 20 | The four-week floor |
| 6 to 7 March 2027, a Saturday and Sunday | 0 | A remainder made entirely of rest days |
| 5 March 2027 to 5 March 2027 | 1 | A single weekday, inclusive of both ends |
| 6 March 2027 to 6 March 2027 | 0 | A single rest day |
| 1 January to 31 December 2027 | 261 | The whole year, as a sum of the twelve months |
Add three calendar-shaped remainder checks: a 30-day month beginning Saturday gives 20; a 31-day month beginning Friday gives 21; and a 29-day February beginning Monday gives 21. The leap-day case adds one weekday unless the first day falls on Saturday or Sunday.
- Rule of thumb: Keep at least one zero-result case and one single-date case in the test set.
If monthly results pass but the annual sum does not
If every month looks right but the year total fails, add the twelve monthly outputs and compare the checksum. For 2027, the expected annual sum is 261 weekdays; the monthly count analysis retains the fuller discussion of how a month's length and starting weekday shape its total.
Formula vs day-by-day sweep
Month
- February 28, Monday
- 20
- March 31, Monday
- 23
- April 30, Thursday
- 22
- May 31, Saturday
- 21
- October 31, Friday
- 21
Formula
- February 28, Monday
- 20
- March 31, Monday
- 23
- April 30, Thursday
- 22
- May 31, Saturday
- 21
- October 31, Friday
- 21
Sweep
- February 28, Monday
- March 31, Monday
- April 30, Thursday
- May 31, Saturday
- October 31, Friday
Treat 261 as an annual checksum, not as a replacement for the month tests. Compare it with the separate year count explanation, then trace any difference to the month row that introduced it. A one-day edge error repeated at month boundaries can become a larger discrepancy in the annual result.
A spreadsheet check gives you another execution path: provide the first and last dates to NETWORKDAYS month edges, which counts both endpoints. Its result should match the day-by-day count. If the two disagree, isolate the failing month before relying on the year sum.
- Rule of thumb: Require both individual month agreement and the annual checksum.
If the range is not a month
If the input is a pay period, notice window, or another span, use the general rule rather than forcing four weeks.
Write its length n as 7w + r, with r from 0 through 6; count five weekdays for every complete week, then inspect the remaining r days from the starting weekday.
from datetime import date, timedelta
def sweep(first, last): # the slow, obvious reference
d, n = first, 0
while d <= last:
n += d.weekday() < 5 # Monday is 0, Sunday is 6
d += timedelta(days=1)
return n
def formula(first, n): # the shortcut under test
w, r = divmod(n, 7)
return 5 * w + sum((first.weekday() + i) % 7 < 5 for i in range(r))
The loop is deliberately less clever: it advances one date at a time and counts Monday through Friday, without reusing the quotient-and-remainder calculation. Compare it over months and arbitrary spans; if the results differ, narrow the problem to the first input where the returned totals diverge.
For an endpoint-based call, convert the pair to a length with a date-difference method, then add one when both endpoints count. This is the inclusive convention used in these vectors. See the date difference formula for the underlying calculation. Crossing December to January does not change the general span rule.
- Rule of thumb: Use the month shortcut only for months; use the general span function everywhere else.
If the output is meant to count working days
If the consumer asks for working days, do not treat a weekday total as final.
These vectors test Monday-to-Friday arithmetic with Saturday and Sunday as rest days; they do not remove public holidays or other closures. The calendar and counting rule for the actual deadline determine which additional dates are excluded.
Keep closure data separate from the arithmetic: business-day counting assumptions explain why the distinction matters, while calendar origins show why different calendars can mark different dates closed. Change the configured rest-day set and rerun the vectors before releasing the code.
A calendar source may be labelled a public-holiday list, federal-holiday schedule, bank-holiday calendar, or local closure list; whichever label applies, it is an input, not a result produced by weekday arithmetic. Do not infer closures from the weekday function, and rerun the vectors whenever the configured rest-day set changes.
When diagnosing a mismatch, check whether the program received a start-plus-length or a pair of endpoints, whether a month-only shortcut was applied to a different span, and whether a weekday total was presented as a working-day total. More checks appear in monthly counting mistakes.
- Rule of thumb: Test weekdays in one layer and calendar closures in another.







