How to Calculate Business Days in JavaScript
From simple weekend skipping to production-ready holiday handling.
Every JavaScript Developer Faces This
You are building a feature that needs to display delivery dates, SLA deadlines, or payment settlement windows. The requirement says “business days,” and your first instinct is to write a loop that skips Saturday and Sunday. That works right up until it does not.
The JavaScript Date object gives you getDay(), which returns 0 for Sunday and 6 for Saturday. That is enough to skip weekends. But business days also exclude public holidays, and that is where the real complexity begins.
The Weekend-Only Approach
Here is the most common starting point. This function adds a given number of business days to a start date, skipping weekends:
function addBusinessDays(startDate, days) {
const result = new Date(startDate);
let added = 0;
while (added < days) {
result.setDate(result.getDate() + 1);
const dayOfWeek = result.getDay();
if (dayOfWeek !== 0 && dayOfWeek !== 6) {
added++;
}
}
return result;
}
// 10 business days from March 9, 2026
const deadline = addBusinessDays(new Date('2026-03-09'), 10);
console.log(deadline.toISOString().slice(0, 10));
// "2026-03-23"This is clean and works for the simplest case. But it assumes every Monday through Friday is a working day, which is incorrect in every country. Christmas Day, Independence Day, bank holidays — none of these are accounted for.
The Hardcoded Holiday List
The next step most developers take is adding an array of holiday dates:
const US_HOLIDAYS_2026 = [
'2026-01-01', // New Year's Day
'2026-01-19', // MLK Jr. Day
'2026-02-16', // Presidents' Day
'2026-05-25', // Memorial Day
'2026-07-03', // Independence Day (observed)
'2026-09-07', // Labor Day
'2026-11-26', // Thanksgiving
'2026-12-25', // Christmas
];
function addBusinessDays(startDate, days, holidays = []) {
const holidaySet = new Set(holidays);
const result = new Date(startDate);
let added = 0;
while (added < days) {
result.setDate(result.getDate() + 1);
const dayOfWeek = result.getDay();
const dateStr = result.toISOString().slice(0, 10);
if (dayOfWeek !== 0 && dayOfWeek !== 6 && !holidaySet.has(dateStr)) {
added++;
}
}
return result;
}This works for a single country and a single year. But maintaining these lists introduces several problems:
- Annual updates: Many holidays fall on different dates each year. Thanksgiving is the fourth Thursday in November. Easter shifts every year. You need to regenerate these lists annually.
- Multi-country support: If your app serves users in the US, UK, and Germany, you need three separate holiday lists. Germany alone has holidays that vary by state.
- Observed holidays: When July 4th falls on a Saturday, the US observes it on Friday. When Christmas falls on a Sunday, the observed day shifts to Monday. These rules differ by country.
- Government changes: Countries add, remove, or move holidays. Your hardcoded list can silently become wrong.
Using the BizDay API Instead
Rather than maintaining holiday data yourself, you can delegate this to the BizDay API. It maintains up-to-date holiday calendars for 30+ countries and handles all the edge cases described above. Here is how to use it in JavaScript.
Check if a Date Is a Business Day
const API_KEY = process.env.BIZDAY_API_KEY;
const BASE_URL = 'https://api.bizday.dev';
async function isBusinessDay(date, country = 'US') {
const res = await fetch(
`${BASE_URL}/v1/check?date=${date}&country=${country}`,
{ headers: { Authorization: `Bearer ${API_KEY}` } }
);
const json = await res.json();
return json.data.is_workday;
}
// Check if Christmas 2026 is a business day in the UK
const result = await isBusinessDay('2026-12-25', 'GB');
console.log(result); // falseAdd Business Days (Holiday-Aware)
async function addBusinessDays(date, days, country = 'US') {
const res = await fetch(
`${BASE_URL}/v1/add?date=${date}&days=${days}&country=${country}`,
{ headers: { Authorization: `Bearer ${API_KEY}` } }
);
const json = await res.json();
return json.data.result_date;
}
// 10 business days from today in Germany
const deadline = await addBusinessDays('2026-03-09', 10, 'DE');
console.log(deadline); // Correctly skips German public holidaysCount Business Days Between Two Dates
This is useful for billing cycles, SLA reporting, and project planning:
async function businessDaysBetween(start, end, country = 'US') {
const res = await fetch(
`${BASE_URL}/v1/between?start=${start}&end=${end}&country=${country}`,
{ headers: { Authorization: `Bearer ${API_KEY}` } }
);
const json = await res.json();
return json.data.workdays;
}
// Working days in Q1 2026 for the US
const count = await businessDaysBetween('2026-01-01', '2026-03-31', 'US');
console.log(`Q1 2026: ${count} working days`);Batch Processing with a Single Request
If you need to check multiple dates at once, the batch endpoint lets you process up to 100 dates in a single API call:
async function batchCheck(dates, country = 'US') {
const res = await fetch(`${BASE_URL}/v1/batch`, {
method: 'POST',
headers: {
Authorization: `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
operation: 'check',
country,
dates,
}),
});
const json = await res.json();
return json.data.results;
}
// Check an entire week at once
const results = await batchCheck([
'2026-03-09', '2026-03-10', '2026-03-11',
'2026-03-12', '2026-03-13',
], 'US');
console.log(results);TypeScript Support
If you are using TypeScript, you can add type safety to your API calls with a simple wrapper:
interface CheckResponse {
success: true;
data: {
date: string;
country: string;
is_workday: boolean;
reason?: string;
holiday?: { name: string; local_name: string; type: string };
};
}
interface AddResponse {
success: true;
data: {
start_date: string;
country: string;
workdays_added: number;
result_date: string;
weekends_skipped: number;
holidays_skipped: string[];
};
}
async function checkDate(date: string, country: string): Promise<CheckResponse> {
const res = await fetch(
`${BASE_URL}/v1/check?date=${date}&country=${country}`,
{ headers: { Authorization: `Bearer ${API_KEY}` } }
);
return res.json();
}Node.js, Deno, and Edge Runtimes
Because the BizDay API uses standard HTTP, it works in any JavaScript runtime that supports fetch. That includes Node.js 18+, Deno, Bun, Cloudflare Workers, and Vercel Edge Functions. There is no client library to install and no dependencies to manage.
When to Use a Library vs. an API
JavaScript libraries like date-fns and Luxon are excellent for date arithmetic, but they do not ship holiday data. You can combine them with a holiday dataset, but then you own the maintenance of that dataset. An API makes sense when:
- You serve users across multiple countries
- You need accurate holiday data without maintaining it yourself
- You want holiday calendars that stay current automatically
- You need consistent results across client and server environments
Getting Started
The BizDay API has a free tier with 10,000 requests per month. No credit card required. You can get an API key in seconds and start making requests from any JavaScript environment. Check the full documentation for all available endpoints, parameters, and response formats.