Best Time For Vacation: Automating Your Holiday Planning with Node.js

This is a side project that I had been thinking about for a long time, to help find the best vacation time. It analyzes holiday data and suggests optimal vacation periods. Planning vacations around public holidays can be tricky—especially if you want to maximize your time off with minimal leave. In this post, I'll walk you through how I built a tool that fetches holiday data, groups sequential holidays, and even suggests the best days to take leave for the longest possible break. We'll cover everything from setup to the logical reasoning behind the code. Table of Contents Project Overview Setting Up the Project Fetching Holiday Data Grouping Sequential Holidays Bridging Holidays with Leaves Bringing It All Together: The Main Function Running the Project Conclusion Project Overview Best Time For Vacation is a Node.js project that: Fetches holiday data from an API (e.g., your company’s HR system) Groups holidays that fall consecutively Suggests the optimal days to take leave for a longer vacation Setting Up the Project First, create a new directory and initialize a Node.js project: npm init -y Install the required dependencies: npm install dayjs node-fetch dotenv Your package.json should look like this: { "name": "bestTimeForVacation", "version": "1.0.0", "type": "module", "scripts": { "start": "node server.js" }, "dependencies": { "dayjs": "^1.11.13", "node-fetch": "2.6.1", "dotenv": "^16.5.0" } } If you need to use environment variables (e.g., API tokens), create a .env file: KEKA_TOKEN="YOUR_KEKA_TOKEN" Fetching Holiday Data We use node-fetch to retrieve holiday data from an API. Here’s a simplified version of the code: import fetch from 'node-fetch'; import 'dotenv/config'; async function fetchHolidays() { const response = await fetch('YOUR_HOLIDAYS_API_URL', { headers: { Authorization: `Bearer ${process.env.KEKA_TOKEN}`, // ...other headers as needed } }); const holidays = await response.json(); return holidays; // Adjust if your API wraps holidays in a .data property } Grouping Sequential Holidays To find holiday streaks, we use the dayjs library for date manipulation. The logic is: Sort all holiday dates. For each holiday, check if the next day is also a holiday. Count how many days in a row are holidays. import dayjs from 'dayjs'; function groupHolidaysSequentially(holidays) { const sorted = holidays.sort(); const result = []; let i = 0; while (i { for (let i = 1; i maxLeaveData.vacationCountWithLeave) { maxLeaveData = { date: leaveDay, vacationCountWithLeave: streak }; } } } }); return { bridgedHolidays, maxLeaveData }; } This function finds the best possible leave day(s) to bridge holidays and maximize your time off. Bringing It All Together: The Main Function So, how do all these helper functions work together when you start the project? The answer lies in the main function, which orchestrates the entire process. Here’s what happens step by step: const main = async () => { try { console.time('Execution Time'); const numOfDaysToCheck = 3; const yearToCheck = 2025; const quarterToCheck = 1; // 1. Fetch holidays from the API let holidays = await fetchHolidays(); // 2. Filter holidays for the desired quarter and year, and extract only the date holidays = holidays .filter((holiday) => checkIsDateInCurrentQuarter(holiday.date, quarterToCheck, yearToCheck)) .map((data) => data.date); // 3. Get all weekends in the specified quarter const weekends = getAllWeekendsInaQuarter(quarterToCheck, yearToCheck); // 4. Combine holidays and weekends const holidayDates = [...holidays]; holidays = groupHolidaysSequentially( holidays.concat(weekends).sort((a, b) => (dayjs(a).isBefore(b) ? -1 : 1)) ); // 5. Find the best days to bridge holidays with leaves const { bridgedHolidays, maxLeaveData } = bridgeHolidaysWithLeaves( holidays, numOfDaysToCheck, holidayDates ); console.timeEnd('Execution Time'); console.log(bridgedHolidays); console.log(maxLeaveData); } catch (err) { console.log(err); process.exit(1); } }; main(); Step-by-Step Breakdown Fetch Holidays: The function starts by fetching all holidays from the API. Filter for Quarter and Year: It then filters these holidays to only include those in a specific quarter and year, focusing your analysis on a relevant time window. Get All Weekends: All weekends in the quarter are calculated, since weekends are natural candidates for extending vacations. Combine and Group: The list of holidays and weekends is merged, sorted, and passed to groupHolidaysSequentially to find streaks of consecutive days off. Bridge with Leaves: The core logic then uses bridgeHolidaysWithLeaves t

Apr 18, 2025 - 15:34
 0
Best Time For Vacation: Automating Your Holiday Planning with Node.js

This is a side project that I had been thinking about for a long time, to help find the best vacation time. It analyzes holiday data and suggests optimal vacation periods.

Planning vacations around public holidays can be tricky—especially if you want to maximize your time off with minimal leave. In this post, I'll walk you through how I built a tool that fetches holiday data, groups sequential holidays, and even suggests the best days to take leave for the longest possible break. We'll cover everything from setup to the logical reasoning behind the code.

Table of Contents

  1. Project Overview
  2. Setting Up the Project
  3. Fetching Holiday Data
  4. Grouping Sequential Holidays
  5. Bridging Holidays with Leaves
  6. Bringing It All Together: The Main Function
  7. Running the Project
  8. Conclusion

Project Overview

Best Time For Vacation is a Node.js project that:

  • Fetches holiday data from an API (e.g., your company’s HR system)
  • Groups holidays that fall consecutively
  • Suggests the optimal days to take leave for a longer vacation

Setting Up the Project

First, create a new directory and initialize a Node.js project:

npm init -y

Install the required dependencies:

npm install dayjs node-fetch dotenv

Your package.json should look like this:

{
  "name": "bestTimeForVacation",
  "version": "1.0.0",
  "type": "module",
  "scripts": {
    "start": "node server.js"
  },
  "dependencies": {
    "dayjs": "^1.11.13",
    "node-fetch": "2.6.1",
    "dotenv": "^16.5.0"
  }
}

If you need to use environment variables (e.g., API tokens), create a .env file:

KEKA_TOKEN="YOUR_KEKA_TOKEN"

Fetching Holiday Data

We use node-fetch to retrieve holiday data from an API. Here’s a simplified version of the code:

import fetch from 'node-fetch';
import 'dotenv/config';

async function fetchHolidays() {
  const response = await fetch('YOUR_HOLIDAYS_API_URL', {
    headers: {
      Authorization: `Bearer ${process.env.KEKA_TOKEN}`,
      // ...other headers as needed
    }
  });
  const holidays = await response.json();
  return holidays; // Adjust if your API wraps holidays in a .data property
}

Grouping Sequential Holidays

To find holiday streaks, we use the dayjs library for date manipulation. The logic is:

  • Sort all holiday dates.
  • For each holiday, check if the next day is also a holiday.
  • Count how many days in a row are holidays.
import dayjs from 'dayjs';

function groupHolidaysSequentially(holidays) {
  const sorted = holidays.sort();
  const result = [];
  let i = 0;

  while (i < sorted.length) {
    let count = 1;
    let current = sorted[i];
    while (
      i + count < sorted.length &&
      dayjs(sorted[i + count]).diff(dayjs(current), 'day') === count
    ) {
      count++;
    }
    result.push({ date: current, numberOfDaysContinuous: count });
    i += count;
  }
  return result;
}

Bridging Holidays with Leaves

The real magic is in suggesting which leave days will maximize your vacation. The logic:

  • For each holiday, simulate taking a leave day before or after.
  • Calculate the new streak length.
  • Suggest the leave day that results in the longest break.

Example logic:

function bridgeHolidaysWithLeaves(holidays, numOfDaysToCheck, holidayDates) {
  let bridgedHolidays = [];
  let maxLeaveData = { date: '', vacationCountWithLeave: 0 };

  holidays.forEach(holiday => {
    for (let i = 1; i <= numOfDaysToCheck; i++) {
      const leaveDay = dayjs(holiday.date).add(i, 'day').format('YYYY-MM-DD');
      if (!holidayDates.includes(leaveDay)) {
        // Simulate adding leave and recalculate streak
        const streak = holiday.numberOfDaysContinuous + 1;
        bridgedHolidays.push({ date: leaveDay, vacationCountWithLeave: streak });
        if (streak > maxLeaveData.vacationCountWithLeave) {
          maxLeaveData = { date: leaveDay, vacationCountWithLeave: streak };
        }
      }
    }
  });

  return { bridgedHolidays, maxLeaveData };
}

This function finds the best possible leave day(s) to bridge holidays and maximize your time off.

Bringing It All Together: The Main Function

So, how do all these helper functions work together when you start the project? The answer lies in the main function, which orchestrates the entire process. Here’s what happens step by step:

const main = async () => {
  try {
    console.time('Execution Time');
    const numOfDaysToCheck = 3;
    const yearToCheck = 2025;
    const quarterToCheck = 1;

    // 1. Fetch holidays from the API
    let holidays = await fetchHolidays();

    // 2. Filter holidays for the desired quarter and year, and extract only the date
    holidays = holidays
      .filter((holiday) => checkIsDateInCurrentQuarter(holiday.date, quarterToCheck, yearToCheck))
      .map((data) => data.date);

    // 3. Get all weekends in the specified quarter
    const weekends = getAllWeekendsInaQuarter(quarterToCheck, yearToCheck);

    // 4. Combine holidays and weekends
    const holidayDates = [...holidays];
    holidays = groupHolidaysSequentially(
      holidays.concat(weekends).sort((a, b) => (dayjs(a).isBefore(b) ? -1 : 1))
    );

    // 5. Find the best days to bridge holidays with leaves
    const { bridgedHolidays, maxLeaveData } = bridgeHolidaysWithLeaves(
      holidays,
      numOfDaysToCheck,
      holidayDates
    );

    console.timeEnd('Execution Time');
    console.log(bridgedHolidays);
    console.log(maxLeaveData);
  } catch (err) {
    console.log(err);
    process.exit(1);
  }
};

main();

Step-by-Step Breakdown

  1. Fetch Holidays:

    The function starts by fetching all holidays from the API.

  2. Filter for Quarter and Year:

    It then filters these holidays to only include those in a specific quarter and year, focusing your analysis on a relevant time window.

  3. Get All Weekends:

    All weekends in the quarter are calculated, since weekends are natural candidates for extending vacations.

  4. Combine and Group:

    The list of holidays and weekends is merged, sorted, and passed to groupHolidaysSequentially to find streaks of consecutive days off.

  5. Bridge with Leaves:

    The core logic then uses bridgeHolidaysWithLeaves to determine which leave days (if any) can be added to maximize your vacation length.

  6. Output:

    Finally, it prints out all possible bridged holidays and highlights the best option for the longest break.

This main function is what runs when you start the server with npm start, tying together all the helper logic to provide actionable vacation suggestions.

Running the Project

Make sure your environment variables are set and start the server:

npm install
npm start

The output will be a list of suggested vacation periods and the optimal leave day for the longest break.

Conclusion

With just a bit of JavaScript and some clever date logic, you can automate your vacation planning and get the most out of your holidays!

Feel free to fork the repo, tweak the logic, or integrate with your favorite calendar app.

Happy holidays and happy coding!

If you have questions or want to see the full source code, check out the GitHub repo.

Let me know in the comments if you’d like a deep dive into any part of the logic!