'How can I use moment.js to add days, excluding weekends?

I'm setting a default follow-up date two days from current date, which currently works:

const Notify = moment().add(2, 'days').toDate();

However, I would like to exclude weekends. So I installed moment WeekDay, but I can't seem to get it to work with adding days to the current date. The documentation calls for:

moment().weekday(0)

But I can't get that to work with adding in two days forward. Any ideas?



Solution 1:[1]

Try: moment-business-days

It should help you.

Example:

var momentBusinessDays = require("moment-business-days")

momentBusinessDays('20-09-2018', 'DD-MM-YYYY').businessAdd(3)._d 

Result:

Tue Sep 25 2018 00:00:00 GMT+0530 (IST)

Solution 2:[2]

This solution is simple, easy to follow, and works well for me:

function addBusinessDays(originalDate, numDaysToAdd) {
  const Sunday = 0;
  const Saturday = 6;
  let daysRemaining = numDaysToAdd;

  const newDate = originalDate.clone();

  while (daysRemaining > 0) {
    newDate.add(1, 'days');
    if (newDate.day() !== Sunday && newDate.day() !== Saturday) {
      daysRemaining--;
    }
  }

  return newDate;
}

Solution 3:[3]

You could also not use external lib and do a simple function like one of these two:

const WEEKEND = [moment().day("Saturday").weekday(), moment().day("Sunday").weekday()]

const addBusinessDays1 = (date, daysToAdd) => {
  var daysAdded = 0,
    momentDate = moment(new Date(date));
  while (daysAdded < daysToAdd) {
    momentDate = momentDate.add(1, 'days');
    if (!WEEKEND.includes(momentDate.weekday())) {
      daysAdded++
    }
  }

  return momentDate;
}
console.log(addBusinessDays1(new Date(), 7).format('MM/DD/YYYY'))
console.log(addBusinessDays1('09-20-2018', 3).format('MM/DD/YYYY'))

// This is the somewhat faster version
const addBusinessDays2 = (date, days) => {
  var d = moment(new Date(date)).add(Math.floor(days / 5) * 7, 'd');
  var remaining = days % 5;
  while (remaining) {
    d.add(1, 'd');
    if (d.day() !== 0 && d.day() !== 6)
      remaining--;
  }
  return d;
};

console.log(addBusinessDays2(new Date(), 7).format('MM/DD/YYYY'))
console.log(addBusinessDays2('09-20-2018', 3).format('MM/DD/YYYY'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.2/moment.min.js"></script>

They are slightly modified from this post and I think are a good alternative to external library you have to carry/deal with (assuming this is the only part you need and not other features of that lib).

Solution 4:[4]

This will do it based on any starting date, and without a costly loop. You calculate the number of weekend days you need to skip over, then just offset by the number of weekdays and weekends, together.

function addWeekdays(year, month, day, numberOfWeekdays) {
    var originalDate = year + '-' + month + '-' + day;
    var futureDate = moment(originalDate);
    var currentDayOfWeek = futureDate.day();            // 0 = Sunday, 1 = Monday, ..., 6 = Saturday
    var numberOfWeekends = Math.floor((currentDayOfWeek + numberOfWeekdays - 1) / 5);   // calculate the number of weekends to skip over

    futureDate.add(numberOfWeekdays + numberOfWeekends * 2, 'days');    // account for the 2 days per weekend

    return futureDate;
}

Solution 5:[5]

var moment = require("moment")
function addWorkingDay(date, days){
    let daysToAdd = days
    const today = moment(date);
    const nextWeekStart = today.clone().add(1, 'week').weekday(1);
    const weekEnd = today.clone().weekday(5);

    const daysTillWeekEnd = Math.max(0, weekEnd.diff(today, 'days'));
    if(daysTillWeekEnd >= daysToAdd) return today.clone().add(daysToAdd, 'days');
    
    daysToAdd = daysToAdd - daysTillWeekEnd - 1;
    
    return nextWeekStart.add(Math.floor(daysToAdd/5), 'week').add(daysToAdd % 5, 'days')
}

Solution 6:[6]

const addWorkingDays = (date: Moment, days: number) => {
  let newDate = date.clone();
  for (let i = 0; i < days; i++) {
    if (newDate.isoWeekday() !== 6 && newDate.isoWeekday() !== 7) {
      newDate = newDate.add(1, "days");
    } else {
      newDate = newDate.add(1, "days");
      i--;
    }
  }
  return newDate.format("YYYY/MM/DD");
};

Solution 7:[7]

I think this code will be faster:

var businessDays = 10;
var days = businessDays + Math.floor((Math.min(moment().day(),5)+businessDays)/6)*2;
moment.add(days, 'days');

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Harshal Y.
Solution 2 zeckdude
Solution 3 Akrion
Solution 4 Ryan Loggerythm
Solution 5 RH-indra Poudel
Solution 6 mouchin777
Solution 7 marc_s