Tips > Building Workflows

Handle Date Math That Expressions Cannot

n8n's built-in expression language supports Luxon for dates, but complex operations like business day calculations, timezone-aware scheduling windows, or fis...

n8n's built-in expression language supports Luxon for dates, but complex operations like business day calculations, timezone-aware scheduling windows, or fiscal quarter logic are easier and more maintainable in a Code node.

Real-world example: A contract renewal workflow needs to calculate the next business day that is at least 30 days out, skipping US federal holidays and weekends.

// Mode: Run Once for Each Item

// US federal holidays for the current year (update annually or fetch dynamically)
const holidays2025 = new Set([
  '2025-01-01', '2025-01-20', '2025-02-17', '2025-05-26',
  '2025-06-19', '2025-07-04', '2025-09-01', '2025-10-13',
  '2025-11-11', '2025-11-27', '2025-12-25',
]);

function isBusinessDay(date) {
  const day = date.getDay();
  if (day === 0 || day === 6) return false; // Weekend
  const iso = date.toISOString().slice(0, 10);
  return !holidays2025.has(iso);
}

function addBusinessDays(start, days) {
  const result = new Date(start);
  let added = 0;
  while (added < days) {
    result.setDate(result.getDate() + 1);
    if (isBusinessDay(result)) added++;
  }
  return result;
}

const contractEnd = new Date($input.item.json.contractEndDate);
const minDate = new Date(contractEnd);
minDate.setDate(minDate.getDate() + 30);

// Find next business day on or after the 30-day mark
let renewalDate = new Date(minDate);
while (!isBusinessDay(renewalDate)) {
  renewalDate.setDate(renewalDate.getDate() + 1);
}

// Also calculate 5-business-day reminder window
const reminderDate = addBusinessDays(renewalDate, -5);

return [{
  json: {
    ...$input.item.json,
    renewalDate: renewalDate.toISOString().slice(0, 10),
    reminderDate: reminderDate.toISOString().slice(0, 10),
    daysUntilRenewal: Math.ceil(
      (renewalDate - new Date()) / (1000 * 60 * 60 * 24)
    ),
  }
}];
```text
This logic would require an unreasonable number of IF and DateTime nodes to replicate on the canvas.

**Related:** [Use Edit Fields in "Map Each" Mode for Simple Renames](../data-transformation/01-use-edit-fields-in-map-each-mode-for-simple-renames.md) | [Configure Payload Size and Binary Data Mode for Large Files](../performance-and-large-files/01-configure-payload-size-and-binary-data-mode-for-large-files.md)

Showcase builds

19 complete workflows from my own projects, each with its n8n workflow JSON to import. Showcase entries link the file at the end of the article.

See the showcase builds

Keep reading

191 entries grouped by topic, from first workflow to queue mode. Free, no signup.

Browse the encyclopedia

Need it built?

I design, build and run n8n systems for clients. Every engagement starts with a $1,500 diagnostic audit, credited toward the build.

Book a 20-minute call