business days
date calculations
AddBusinessDays function
GetBusinessDays function
programming utilities

AddBusinessDays and GetBusinessDays

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

AddBusinessDays and GetBusinessDays are common date utilities used in invoicing, shipping, payroll, and scheduling systems. They sound simple until weekends, holidays, negative offsets, and inclusive-versus-exclusive counting rules enter the picture. A solid implementation starts by defining what counts as a business day and then applying that rule consistently in both directions.

Define the Business-Day Rule First

Before writing code, decide exactly what your application means by a business day.

Typical rules:

  • Monday through Friday are working days.
  • Saturday and Sunday are excluded.
  • A configurable holiday set is also excluded.
  • The start day may or may not count, depending on the API contract.

If two functions use slightly different rules, your system produces inconsistent due dates and date differences.

Example Implementation in Python

The simplest approach is to move one day at a time and skip non-business dates.

python
1from datetime import date, timedelta
2
3
4def is_business_day(day: date, holidays: set[date]) -> bool:
5    return day.weekday() < 5 and day not in holidays
6
7
8def add_business_days(start: date, days: int, holidays: set[date] | None = None) -> date:
9    holidays = holidays or set()
10    if days == 0:
11        return start
12
13    step = 1 if days > 0 else -1
14    remaining = abs(days)
15    current = start
16
17    while remaining > 0:
18        current += timedelta(days=step)
19        if is_business_day(current, holidays):
20            remaining -= 1
21
22    return current
23
24
25holidays = {date(2026, 1, 1)}
26print(add_business_days(date(2025, 12, 31), 2, holidays))

This is easy to reason about and correct for moderate workloads.

Count Business Days Between Two Dates

GetBusinessDays usually means counting working days in a date range. You need to define whether the count includes the start date, the end date, or both.

One clear contract is: count business days from start up to but not including end.

python
1from datetime import date, timedelta
2
3
4def get_business_days(start: date, end: date, holidays: set[date] | None = None) -> int:
5    holidays = holidays or set()
6    if start == end:
7        return 0
8
9    step = 1 if end > start else -1
10    count = 0
11    current = start
12
13    while current != end:
14        current += timedelta(days=step)
15        if current != end and is_business_day(current, holidays):
16            count += step
17
18    return count
19
20
21holidays = {date(2026, 1, 1)}
22print(get_business_days(date(2025, 12, 29), date(2026, 1, 5), holidays))

If your application needs a different inclusion rule, change the contract and document it explicitly.

Holidays Should Be Data, Not Hardcoded Logic

Weekend logic is stable, but holidays vary by country, business unit, and year. Put holidays in data structures, configuration files, or a database table rather than scattering them across conditionals.

Example JSON-like source:

python
1from datetime import date
2
3us_company_holidays = {
4    date(2026, 1, 1),
5    date(2026, 7, 3),
6    date(2026, 12, 25),
7}

That makes testing easier and allows business users to update schedules without rewriting date logic.

Performance Considerations

Day-by-day iteration is usually fine for due dates and short ranges, but it becomes expensive for large date spans or batch calculations.

Practical options:

  • keep the simple loop for correctness-first code
  • precompute holiday sets for fast lookup
  • optimize with week-based arithmetic only after tests exist

The most common mistake is writing a clever optimized formula before confirming the business rules.

Negative Offsets and Reverse Ranges

Real systems often need to go backward as well as forward.

Examples:

  • subtract 5 business days from a settlement date
  • compute business days remaining until a deadline
  • compare SLA dates in reverse order

If your code handles only positive increments, it will break once backdating or rollback features appear. Build reverse traversal into the function from the beginning.

Testing Edge Cases

Business-day utilities should always have tests around boundaries.

python
1def run_tests():
2    holidays = {date(2026, 1, 1)}
3    assert add_business_days(date(2025, 12, 31), 1, holidays) == date(2026, 1, 2)
4    assert add_business_days(date(2026, 1, 5), -1, holidays) == date(2026, 1, 2)
5    assert get_business_days(date(2026, 1, 5), date(2026, 1, 5), holidays) == 0
6
7
8run_tests()

Weekend crossings, holiday crossings, and zero-length ranges are the first cases to lock down.

Common Pitfalls

  • Not defining whether the start date counts. Fix: document the counting contract before writing code.
  • Hardcoding holiday rules in logic. Fix: treat holidays as data input.
  • Supporting only positive day offsets. Fix: handle negative values with the same function.
  • Optimizing too early with complicated arithmetic. Fix: start with a correct loop and profile later.
  • Forgetting to test month-end and year-end boundaries. Fix: add explicit regression tests around weekends and holidays.

Summary

  • Business-day utilities depend on clear counting rules.
  • Keep weekend logic separate from holiday data.
  • Support both forward and backward movement through dates.
  • Start with a correct implementation before optimizing.
  • Test inclusion rules and calendar boundaries explicitly.

Course illustration
Course illustration

All Rights Reserved.