Add Business Days in Java: Skip Weekends and Holidays

Add business days in Java by skipping weekends and holidays with LocalDate, subtract them with the same method, and support Fri-Sat weekends.

Counting three business days from Friday 2026-10-09 skips the weekend and the Monday holiday and ends on Thursday 2026-10-15

To add business days in Java, we step through the calendar with LocalDate.plusDays(1) and count only the days that are neither a weekend day nor a holiday, until the count reaches the requested number. The JDK leaves business days to us, because each country and each company has its own weekend days and holidays.

We use business-day arithmetic for delivery estimates, payment due dates, support SLAs and settlement dates. One method that accepts a negative number handles subtraction too.

The following example adds and subtracts three business days from Friday, October 9, 2026, with and without a holiday on Monday, October 12. The addBusinessDays() method comes from section 2.

LocalDate orderDate = LocalDate.of(2026, 10, 9);                                  // a Friday
LocalDate shipBy = addBusinessDays(orderDate, 3, Set.of());                       // 2026-10-14
LocalDate shipByHoliday = addBusinessDays(orderDate, 3, Set.of(LocalDate.of(2026, 10, 12)));   // 2026-10-15
LocalDate threeBack = addBusinessDays(orderDate, -3, Set.of());                   // 2026-10-06

Notice that the start date never counts, and the weekend and the holiday are skipped. The article builds the method, supports other weekend days and yearly holidays, adds a faster version for long offsets, and keeps the time of day for LocalDateTime values.

1. Deciding Whether a Date Is a Business Day

A business day is a date that is not a weekend day and not a holiday. The weekend check reads getDayOfWeek() from the LocalDate and compares it with DayOfWeek constants, and the holiday check looks the date up in a Set. A HashSet answers contains() in constant time, which matters when the method checks hundreds of dates.

static boolean isBusinessDay(LocalDate date, Set<LocalDate> holidays) {
    DayOfWeek day = date.getDayOfWeek();
    boolean weekend = day == DayOfWeek.SATURDAY || day == DayOfWeek.SUNDAY;
    return !weekend && !holidays.contains(date);
}
Set<LocalDate> holidays = Set.of(LocalDate.of(2026, 10, 12));
boolean friday = isBusinessDay(LocalDate.of(2026, 10, 9), holidays);     // true
boolean saturday = isBusinessDay(LocalDate.of(2026, 10, 10), holidays);  // false
boolean holiday = isBusinessDay(LocalDate.of(2026, 10, 12), holidays);   // false

The check if a date is a weekend article covers the weekend test on its own, including LocalDateTime and ZonedDateTime inputs.

2. An addBusinessDays() Method That Also Subtracts

The method moves one day at a time in the direction of the sign and decrements a counter on each business day. A positive number moves forward, a negative number moves back, and zero returns the start date unchanged.

Counting three business days from Friday 2026-10-09 skips the weekend and the Monday holiday and ends on Thursday 2026-10-15
The start date is not counted; weekend days and holidays are stepped over without decrementing the counter
static LocalDate addBusinessDays(LocalDate date, int days, Set<LocalDate> holidays) {
    Objects.requireNonNull(date, "date");
    Objects.requireNonNull(holidays, "holidays");
    int step = days < 0 ? -1 : 1;
    int remaining = Math.abs(days);
    LocalDate result = date;
    while (remaining > 0) {
        result = result.plusDays(step);
        if (isBusinessDay(result, holidays)) {
            remaining--;
        }
    }
    return result;
}
Set<LocalDate> noHolidays = Set.of();
LocalDate fromSaturday = addBusinessDays(LocalDate.of(2026, 10, 10), 1, noHolidays);   // 2026-10-12
LocalDate zeroDays = addBusinessDays(LocalDate.of(2026, 10, 10), 0, noHolidays);      // 2026-10-10
LocalDate tenBack = addBusinessDays(LocalDate.of(2026, 10, 9), -10, noHolidays);      // 2026-09-25

The loop condition must be remaining > 0; a condition such as days >= 0 runs one extra round and moves one business day too far. For example, with days >= 0, 8 business days before Tuesday, May 5, 2020 come out as April 22 instead of April 23.

A start date on a weekend is a business rule, not a technical one. With zero days, our method returns the Saturday itself, so when the rule says “the next business day on or after the date”, we call addBusinessDays(date, 1, holidays) on the day before, or add a separate nextOrSameBusinessDay() helper.

3. Holiday Lists and Other Weekend Days

Say an online shop promises delivery within three business days and ships to Germany and Saudi Arabia. The holidays differ, and in Saudi Arabia the weekend is Friday and Saturday. We pass both rules in, so the same method serves every warehouse.

static boolean isWorkingDay(LocalDate date, Set<DayOfWeek> weekend, Set<LocalDate> holidays, Set<MonthDay> yearlyHolidays) {
    return !weekend.contains(date.getDayOfWeek())
            && !holidays.contains(date)
            && !yearlyHolidays.contains(MonthDay.from(date));
}

A MonthDay holds a month and a day without a year, so fixed-date holidays such as December 25 are listed once instead of once per year. Holidays that move, such as Easter Monday or the second Monday of October, stay in the Set<LocalDate>, which an app loads from a database table or a configuration file.

Set<DayOfWeek> friSat = EnumSet.of(DayOfWeek.FRIDAY, DayOfWeek.SATURDAY);
Set<DayOfWeek> satSun = EnumSet.of(DayOfWeek.SATURDAY, DayOfWeek.SUNDAY);
Set<MonthDay> fixed = Set.of(MonthDay.of(12, 25), MonthDay.of(1, 1));
boolean fridayInRiyadh = isWorkingDay(LocalDate.of(2026, 10, 9), friSat, Set.of(), Set.of());   // false
boolean sundayInRiyadh = isWorkingDay(LocalDate.of(2026, 10, 11), friSat, Set.of(), Set.of()); // true
boolean christmas = isWorkingDay(LocalDate.of(2026, 12, 25), satSun, Set.of(), fixed);          // false

The addBusinessDays() loop stays the same and calls isWorkingDay() instead of isBusinessDay(). An EnumSet is the natural type for the weekend days, because it stores a set of enum constants as a bit mask.

4. Skipping Whole Weeks for Long Offsets

The loop checks every calendar day, so 250 business days means about 350 iterations. That cost does not matter for a single call, but a batch job that computes due dates for a million invoices can skip the loop for whole weeks. Every run of 7 calendar days after any start date holds 5 weekdays, no more and no less, so we jump (days – 1) / 5 weeks at once and count the rest with the loop.

static LocalDate addWeekdays(LocalDate date, int days) {
    if (days <= 0) {
        return addBusinessDays(date, days, Set.of());
    }
    int weeks = (days - 1) / 5;
    LocalDate result = date.plusWeeks(weeks);
    return addBusinessDays(result, days - weeks * 5, Set.of());
}
LocalDate start = LocalDate.of(2026, 10, 10);
LocalDate yearOfWork = addWeekdays(start, 250);                        // 2027-09-24
boolean sameAsLoop = IntStream.rangeClosed(1, 1000).allMatch(n -> addWeekdays(start, n).equals(addBusinessDays(start, n, Set.of())));   // true

The shortcut covers weekends only. With holidays, we either keep the plain loop, which is fast enough for most apps, or apply the shortcut and walk forward once more for each holiday that falls on a weekday in the skipped range.

5. Business Days on LocalDateTime and ZonedDateTime

Business days are a calendar concept, so we do the counting on the date part and put the time back. The method with(LocalDate) on a LocalDateTime or a ZonedDateTime replaces the date and keeps the time of day, and the zoned version also keeps the zone.

LocalDateTime ticketOpened = LocalDateTime.of(2026, 10, 9, 16, 0);
LocalDateTime slaDue = ticketOpened.with(addBusinessDays(ticketOpened.toLocalDate(), 2, Set.of()));   // 2026-10-13T16:00
ZonedDateTime paymentAt = ZonedDateTime.of(2026, 10, 9, 10, 0, 0, 0, ZoneId.of("Europe/Berlin"));
ZonedDateTime settles = paymentAt.with(addBusinessDays(paymentAt.toLocalDate(), 1, Set.of()));       // 2026-10-12T10:00+02:00[Europe/Berlin]

For the opposite question, how many business days lie between two dates, the business days between two dates article counts them with datesUntil() and a formula.

6. Add Business Days in Java FAQs

Delivery dates and SLA rules lead to these follow-up questions.

6.1. Does Java have a built-in method to add business days?

No. The java.time API has no notion of holidays or working weeks, so we write a small loop such as addBusinessDays(). Financial libraries ship business-day calendars, but most apps need only a holiday table and the loop.

6.2. Is the start date counted as a business day?

No. In our method, as in the WORKDAY function of spreadsheets, the first counted day is the day after the start date. Adding one business day to a Friday gives the next Monday.

6.3. How do we subtract business days in Java?

We pass a negative number to addBusinessDays(), for example -3. The loop steps backwards with plusDays(-1) and uses the same weekend and holiday checks.

6.4. How do we add business days to a java.util.Date?

We convert it with date.toInstant().atZone(zone).toLocalDate(), call addBusinessDays(), and convert back with Date.from(result.atStartOfDay(zone).toInstant()) if the old API needs a Date. The LocalDate to Date article shows both directions.

7. Conclusion

Adding business days is a loop over plusDays() that counts only the dates that pass a business-day check. With a step of -1, the same loop subtracts, and the loop condition remaining > 0 keeps the count exact.

Weekend days and holidays are data, so we pass them in as a Set<DayOfWeek>, a Set<LocalDate> and a Set<MonthDay>. For long offsets without holidays, jumping whole weeks gives the same result with far fewer iterations. Days, months and years without the business rules are covered in adding days, months and years, and the Java date and time guide links the rest.

8. References

Happy Learning !!

Source Code on Github

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.