// Calculate delivery date: 5 business days from today, US holidays
const response = await fetch(
"https://worlddataapi.com/v1/business-days/US/add?start=2026-01-15&days=5",
{ headers: { "X-API-Key": "YOUR_API_KEY" } },
);
const data = await response.json();
console.log(`Estimated delivery: ${data.result}`); // "2026-01-22"
import requests
response = requests.get(
"https://worlddataapi.com/v1/business-days/US/add",
params={"start": "2026-01-15", "days": 5},
headers={"X-API-Key": "YOUR_API_KEY"}
)
data = response.json()
print(f"Estimated delivery: {data['result']}") # "2026-01-22"
curl -X GET "https://worlddataapi.com/v1/business-days/US/add?start=2026-01-15&days=5" \
-H "X-API-Key: YOUR_API_KEY"
Promising a delivery date and missing it damages customer trust. This guide covers building delivery estimates that account for weekends, holidays, and the complexity of international shipping.
The Challenge#
Delivery date calculation seems straightforward until you encounter:
Weekends and holidays that vary by country and region
Non-Western workweeks (Israel uses Sunday-Thursday, UAE uses Monday-Saturday)
Multi-country shipping where origin and destination have different holiday schedules
Half-day holidays that some businesses observe as full closures
Year-end complexity when orders span December into January
A US-based e-commerce site shipping to the UK must account for US warehouse holidays during processing, UK holidays during final delivery, and the fact that Boxing Day (Dec 26) is a UK holiday but not a US one.
Prerequisites#
Before starting, you need:
A World Data API key with Premium tier access (business day calculations require Premium)
Basic familiarity with REST APIs
Node.js 18+ or Python 3.8+ for the code examples
Note: Business day calculations are a Premium feature. The Free tier does not include access to the
/business-daysendpoints. View pricing for tier details.
The Problem with Naive Calculations#
A common approach:
// DON'T DO THIS
function getDeliveryDate(orderDate, shippingDays) {
const delivery = new Date(orderDate);
delivery.setDate(delivery.getDate() + shippingDays);
return delivery;
}
// Order on Friday, Dec 18 with 5-day shipping
getDeliveryDate("2026-12-18", 5);
// Returns Dec 23 — but that ignores weekends AND Christmas
This breaks when:
The delivery window includes weekends
Holidays fall in the shipping period
Origin and destination have different holiday schedules
The origin country has a non-Western workweek
Basic Business Day Calculation#
Account for weekends and origin country holidays:
async function calculateDeliveryDate(origin, orderDate, businessDays) {
const response = await fetch(
`https://worlddataapi.com/v1/business-days/${origin}/add?` +
`start=${orderDate}&days=${businessDays}`,
{ headers: { "X-API-Key": API_KEY } },
);
const data = await response.json();
return data.result;
}
// 5 business days from order, accounting for US holidays
const delivery = await calculateDeliveryDate("US", "2026-12-18", 5);
// Returns "2026-12-29" — skips weekends AND Christmas
Multi-Country Shipping#
International orders involve holidays in both origin and destination countries. A package can't be processed if the origin warehouse is closed, and can't be delivered if the destination country has a holiday.
Strategy 1: Origin-Based Calculation#
Calculate using origin country holidays. The package ships when the warehouse operates; destination delivery depends on local carriers.
async function calculateInternationalDelivery(
origin,
destination,
orderDate,
config,
) {
const { processingDays, transitDays } = config;
// Processing uses origin business days
const processedDate = await addBusinessDays(
origin,
orderDate,
processingDays,
);
// Transit is calendar days (planes fly on holidays)
const transitDate = addCalendarDays(processedDate, transitDays);
// Final delivery uses destination business days
const deliveryDate = await getNextBusinessDay(destination, transitDate);
return {
orderDate,
processedDate,
estimatedDelivery: deliveryDate,
};
}
async function addBusinessDays(location, start, days) {
const response = await fetch(
`https://worlddataapi.com/v1/business-days/${location}/add?start=${start}&days=${days}`,
{ headers: { "X-API-Key": API_KEY } },
);
return (await response.json()).result;
}
async function getNextBusinessDay(location, date) {
const response = await fetch(
`https://worlddataapi.com/v1/business-days/${location}/next?from=${date}`,
{ headers: { "X-API-Key": API_KEY } },
);
return (await response.json()).next;
}
function addCalendarDays(date, days) {
const d = new Date(date);
d.setDate(d.getDate() + days);
return d.toISOString().split("T")[0];
}
Strategy 2: Combined Holiday Check#
For more accuracy, check both countries:
async function getDeliveryWithBothCountries(
origin,
destination,
orderDate,
totalDays,
) {
// Get holidays for both countries
const [originHolidays, destHolidays] = await Promise.all([
getHolidaySet(origin, getYear(orderDate)),
getHolidaySet(destination, getYear(orderDate)),
]);
// Merge holiday sets
const allHolidays = new Set([...originHolidays, ...destHolidays]);
// Calculate manually with combined holidays
let current = new Date(orderDate);
let businessDaysAdded = 0;
while (businessDaysAdded < totalDays) {
current.setDate(current.getDate() + 1);
const dateStr = current.toISOString().split("T")[0];
if (isWeekday(current) && !allHolidays.has(dateStr)) {
businessDaysAdded++;
}
}
return current.toISOString().split("T")[0];
}
Real-World Delivery Calculation#
A complete implementation handling common scenarios:
class DeliveryCalculator {
constructor(apiKey) {
this.apiKey = apiKey;
this.baseUrl = "https://worlddataapi.com/v1";
}
async calculate(options) {
const {
origin,
destination,
orderDate,
orderTime,
cutoffTime = "14:00",
processingDays = 1,
shippingMethod,
} = options;
// Check if order was placed before cutoff
const effectiveOrderDate = this.getEffectiveOrderDate(
orderDate,
orderTime,
cutoffTime,
origin,
);
// Calculate processing completion
const processedDate = await this.addBusinessDays(
origin,
effectiveOrderDate,
processingDays,
);
// Calculate transit time based on shipping method
const transitDays = this.getTransitDays(
shippingMethod,
origin,
destination,
);
// Add transit (calendar days for air, business days for ground)
let arrivalDate;
if (
shippingMethod.includes("air") ||
shippingMethod.includes("express")
) {
arrivalDate = this.addCalendarDays(processedDate, transitDays);
} else {
arrivalDate = await this.addBusinessDays(
origin,
processedDate,
transitDays,
);
}
// Ensure delivery falls on a business day in destination
const deliveryDate = await this.ensureBusinessDay(
destination,
arrivalDate,
);
return {
orderDate,
effectiveOrderDate,
processedDate,
arrivalDate,
estimatedDelivery: deliveryDate,
shippingMethod,
businessDaysTotal: await this.countBusinessDays(
origin,
orderDate,
deliveryDate,
),
};
}
getEffectiveOrderDate(orderDate, orderTime, cutoffTime, origin) {
// If ordered after cutoff, processing starts next business day
if (orderTime && orderTime > cutoffTime) {
// For now, add one calendar day (simplified)
// Production code should check if next day is a business day
const next = new Date(orderDate);
next.setDate(next.getDate() + 1);
return next.toISOString().split("T")[0];
}
return orderDate;
}
getTransitDays(method, origin, destination) {
// Simplified — real implementation uses carrier data
const domestic = origin.substring(0, 2) === destination.substring(0, 2);
const transitTimes = {
ground: domestic ? 5 : 14,
express: domestic ? 2 : 5,
overnight: 1,
"international-air": 7,
"international-economy": 21,
};
return transitTimes[method] || 7;
}
async addBusinessDays(location, start, days) {
const response = await fetch(
`${this.baseUrl}/business-days/${location}/add?start=${start}&days=${days}`,
{ headers: { "X-API-Key": this.apiKey } },
);
return (await response.json()).result;
}
async ensureBusinessDay(location, date) {
const response = await fetch(
`${this.baseUrl}/business-days/${location}?date=${date}`,
{ headers: { "X-API-Key": this.apiKey } },
);
const data = await response.json();
if (data.is_business_day) {
return date;
}
return data.next_business_day;
}
async countBusinessDays(location, start, end) {
const response = await fetch(
`${this.baseUrl}/business-days/${location}/count?start=${start}&end=${end}`,
{ headers: { "X-API-Key": this.apiKey } },
);
return (await response.json()).business_days;
}
addCalendarDays(date, days) {
const d = new Date(date);
d.setDate(d.getDate() + days);
return d.toISOString().split("T")[0];
}
}
Usage#
const calculator = new DeliveryCalculator(process.env.API_KEY);
const estimate = await calculator.calculate({
origin: "US-CA", // Shipping from California
destination: "GB", // Delivering to UK
orderDate: "2026-12-18",
orderTime: "10:30",
cutoffTime: "14:00",
processingDays: 2,
shippingMethod: "international-air",
});
console.log(estimate);
// {
// orderDate: '2026-12-18',
// effectiveOrderDate: '2026-12-18',
// processedDate: '2026-12-22',
// arrivalDate: '2026-12-29',
// estimatedDelivery: '2026-12-29',
// shippingMethod: 'international-air',
// businessDaysTotal: 7
// }
Displaying Delivery Estimates#
Date Range Instead of Single Date#
Given uncertainty in transit times, show a range:
function formatDeliveryEstimate(estimate, bufferDays = 2) {
const earliest = estimate.estimatedDelivery;
const latest = addCalendarDays(earliest, bufferDays);
const formatOptions = { weekday: "short", month: "short", day: "numeric" };
return {
earliest: new Date(earliest).toLocaleDateString("en-US", formatOptions),
latest: new Date(latest).toLocaleDateString("en-US", formatOptions),
display: `${formatDate(earliest)} - ${formatDate(latest)}`,
};
}
// "Fri, Dec 25 - Sun, Dec 27"
Holiday Warnings#
Alert customers about holiday delays:
async function getDeliveryWarnings(origin, destination, startDate, endDate) {
const warnings = [];
// Check origin holidays
const originHolidays = await getHolidaysInRange(origin, startDate, endDate);
if (originHolidays.length > 0) {
warnings.push({
type: "origin-holiday",
message: `Shipping may be delayed due to ${originHolidays[0].name} in origin country.`,
});
}
// Check destination holidays
const destHolidays = await getHolidaysInRange(
destination,
startDate,
endDate,
);
if (destHolidays.length > 0) {
warnings.push({
type: "destination-holiday",
message: `Delivery may be delayed due to ${destHolidays[0].name}.`,
});
}
// Peak season warning
const month = new Date(startDate).getMonth();
if (month === 11 || month === 0) {
warnings.push({
type: "peak-season",
message: "Holiday season may cause additional delays.",
});
}
return warnings;
}
Regional Considerations#
US State Holidays#
California orders may be delayed on César Chávez Day (March 31) when shipping from California warehouses:
// Use state-level location for accuracy
const estimate = await calculator.calculate({
origin: "US-CA", // Not just 'US'
destination: "US-NY",
// ...
});
Non-Western Workweeks#
Shipping from Israel or the UAE? Their workweek differs:
// Israel: Sunday-Thursday
// The API handles this automatically
const estimate = await calculator.calculate({
origin: "IL",
destination: "US",
orderDate: "2026-01-02", // Friday — weekend in Israel
// ...
});
// Processing starts Sunday, not Monday
Caching for Performance#
Delivery estimates are calculated frequently. Cache holiday data:
class CachedDeliveryCalculator extends DeliveryCalculator {
constructor(apiKey) {
super(apiKey);
this.holidayCache = new Map();
}
async getHolidaySet(location, year) {
const key = `${location}:${year}`;
if (!this.holidayCache.has(key)) {
const response = await fetch(
`${this.baseUrl}/holidays/${location}?year=${year}`,
{ headers: { "X-API-Key": this.apiKey } },
);
const data = await response.json();
this.holidayCache.set(
key,
new Set(data.holidays.map((h) => h.date)),
);
}
return this.holidayCache.get(key);
}
}
Common Pitfalls#
Half-Day Holidays#
The API treats half-day holidays (such as Christmas Eve in some countries) as full holidays. This is a known limitation.
Important: The World Data API does not distinguish between half-day and full-day holidays. Days like Christmas Eve, New Year's Eve, or the day before Thanksgiving are treated as full holidays in the business day calculation. If your business operates on half-days, you may need to add manual adjustments to your calculations.
For example, if your warehouse operates until noon on Christmas Eve, the API will skip that day entirely. Consider adding custom logic for these edge cases:
const halfDayHolidays = {
US: ["12-24", "12-31"], // Christmas Eve, New Year's Eve
DE: ["12-24", "12-31"], // Heiligabend, Silvester
};
function isHalfDay(location, date) {
const monthDay = date.slice(5); // "MM-DD"
return halfDayHolidays[location]?.includes(monthDay) || false;
}
Cutoff Time Timezone#
Ensure cutoff time matches warehouse timezone:
function isBeforeCutoff(orderTime, cutoffTime, warehouseTimezone) {
const orderMoment = new Date(orderTime);
const cutoff = new Date(orderTime);
// Parse cutoff time in warehouse timezone
const [hours, minutes] = cutoffTime.split(":");
cutoff.setHours(parseInt(hours), parseInt(minutes), 0, 0);
// Compare in same timezone
return orderMoment < cutoff;
}
Year Boundaries#
Orders near year-end may span two years:
async function getHolidaysForRange(location, startDate, endDate) {
const startYear = new Date(startDate).getFullYear();
const endYear = new Date(endDate).getFullYear();
const holidays = [];
for (let year = startYear; year <= endYear; year++) {
const yearHolidays = await getHolidays(location, year);
holidays.push(...yearHolidays);
}
return holidays.filter((h) => h.date >= startDate && h.date <= endDate);
}
Carrier Operating Days#
Some carriers don't deliver on Saturdays. Adjust final delivery:
async function adjustForCarrier(deliveryDate, carrier, destination) {
const date = new Date(deliveryDate);
const dayOfWeek = date.getDay();
if (carrier.noSaturdayDelivery && dayOfWeek === 6) {
// Push to Monday (or next business day)
return getNextBusinessDay(destination, deliveryDate);
}
if (carrier.noSundayDelivery && dayOfWeek === 0) {
return getNextBusinessDay(destination, deliveryDate);
}
return deliveryDate;
}
Testing#
describe("DeliveryCalculator", () => {
it("skips Christmas", async () => {
const calc = new DeliveryCalculator(API_KEY);
const result = await calc.calculate({
origin: "US",
destination: "US",
orderDate: "2026-12-22",
processingDays: 1,
shippingMethod: "ground",
});
// Should skip Dec 25
expect(result.estimatedDelivery).not.toBe("2026-12-25");
});
it("handles Friday orders after cutoff", async () => {
const calc = new DeliveryCalculator(API_KEY);
const result = await calc.calculate({
origin: "US",
destination: "US",
orderDate: "2026-01-16", // Friday
orderTime: "15:00", // After 2pm cutoff
processingDays: 1,
shippingMethod: "overnight",
});
// Processing starts Monday, delivery Tuesday
expect(result.processedDate).toBe("2026-01-20");
});
});
Summary#
Building accurate delivery date calculations requires handling several complexities:
Use business day calculations instead of naive calendar day additions to skip weekends and holidays automatically
Account for origin and destination holidays when shipping internationally
Implement cutoff times in the correct timezone to determine when processing starts
Handle year boundaries by fetching holidays for multiple years when orders span December-January
Add buffer time and display date ranges rather than single dates to account for carrier variability
Adjust for carrier schedules since not all carriers deliver on weekends
The World Data API handles regional workweeks (like Israel's Sunday-Thursday) and country-specific holidays automatically, but remember that half-day holidays are treated as full days off.
Ready to implement accurate delivery estimates? Get your API key and start with 60 free requests per day, or upgrade to Premium for access to business day calculations.
Next Steps#
How to Calculate Business Days in JavaScript — Foundation for shipping calculations
Adding International Holiday Support to Your App — Holiday data patterns
Caching Strategies for Reference Data APIs — Optimize API usage