Get next day, skip weekends
Asked Answered
E

6

6

I want to generate next working day using JavaScript.

This is my code as of now

var today = new Date();
    today.setDate(today.getDate());
    var tdd = today.getDate();
    var tmm = today.getMonth()+1;
    var tyyyy = today.getYear();

    var date = new Date();

    date.setDate(date.getDate()+3);

Problem is, on Fridays it returns Saturday's date whereas I want it to be Monday

Einstein answered 25/8, 2016 at 6:13 Comment(2)
Look at the day (today.getDay()), if it's 5 (Friday) add 3, if it's 6 (Saturday) add 2, otherwise add 1.Sorcha
Tack on an if statement that says if the date's day of the week is Saturday, add two more days. Add another if statement to check for Sunday.Midget
Z
17

This will choose the next working day when a date is passed to it.

I suggest you normalise the date you pass, so you will not be surprised around summertime/wintertime change

Updated in 2023

// update and return passed date object to next working day
const getNextWork = date => {
  let day = date.getDay(), add = 1;
  if (day === 6)           add = 2; else 
  if (day === 5)           add = 3;
  date.setDate(date.getDate() + add); // will correctly handle 31+1 > 32 > 1st next month
  return date;
};


// tests:
const dt = new Intl.DateTimeFormat("en-US", {
  weekday: "short",
  year: "numeric",
  month: "long",
  day: "numeric",
  timeZone: "UTC",
  timeZoneName: "short",
  hour: "numeric",
  minute: "numeric",
});
const aDay = 24 * 60 * 60 * 1000;
// 26th of March 2023 is daylight savings date in my country
let date = new Date(2023, 2, 24, 15, 0, 0, 0).getTime();

for (let i = 0; i < 7; i++) {
  const d = new Date(date + i * aDay);
  console.log(dt.format(d), "-->", dt.format(getNextWork(d)));
}

If you do not want to update the passed date object have this instead

// find next working day and return a new date for that date
const getNewNextWork = date => {
  const dateCopy = new Date(date);
  let day = dateCopy.getDay(), add = 1;
  if (day === 6)           add = 2; else 
  if (day === 5)           add = 3;
  dateCopy.setDate(dateCopy.getDate() + add); // Modifying the copy, not the original date
  return dateCopy;
};

Older code:

var today = new Date(2016, 7, 26,12,0,0,0,0); // Friday at noon
console.log("today, Monday",today,"day #"+today.getDay());
var next = new Date(today.getTime());
next.setDate(next.getDate()+1); // tomorrow
while (next.getDay() == 6 || next.getDay() == 0) next.setDate(next.getDate() + 1);
console.log("no change    ",next,"day #"+next.getDay());
console.log("-------");
// or without a loop:

function getNextWork(d) {
  d.setDate(d.getDate()+1); // tomorrow
  if (d.getDay()==0) d.setDate(d.getDate()+1);
  else if (d.getDay()==6) d.setDate(d.getDate()+2);
  return d;
}
next = getNextWork(today); // Friday
console.log("today, Friday",today);
console.log("next, Monday ",next);
console.log("-------");
today = new Date(2016, 7, 29,12,0,0,0); // Monday at noon
next = getNextWork(today);              // Still Monday at noon
console.log("today, Monday",today);
console.log("no change    ",next);
console.log("-------");

// Implementing Rob's comment

function getNextWork1(d) {
  var day = d.getDay(),add=1;
  if (day===5) add=3;
  else if (day===6) add=2;
  d.setDate(d.getDate()+add);  
  return d;
}
today = new Date(2016, 7, 26,12,0,0,0,0); // Friday at noon
next = getNextWork1(today);               // Friday
console.log("today, Friday",today);
console.log("next, Monday ",next);
console.log("-------");
today = new Date(2016, 7, 26,12,0,0,0,0); // Monday at noon
next = getNextWork1(today); // Monday
console.log("today, Monday",today);
console.log("no change    ",next);
Zinciferous answered 25/8, 2016 at 6:17 Comment(3)
You should note that the date is passed by reference. If you call getNextWork multiple with the same variable it will keep adding days.Quillon
Sure, but that is not a problem (here) in my eyes. The function will add days to the date object passed. That is what it does. The loop creates a new date for each call. I will add your warning and a function that will make a copy, but for my example it is not an issue.Zinciferous
No, for your example it's not a problem. Just pointing viewers to keep this in mind. I would go for the answer of @SorchaQuillon
S
5

You can add 1 day at at time until you get to a day that isn't Saturday or Sunday:

function getNextBusinessDay(date) {
  // Copy date so don't affect original
  date = new Date(+date);
  // Add days until get not Sat or Sun
  do {
    date.setDate(date.getDate() + 1);
  } while (!(date.getDay() % 6))
  return date;
}

// today,    Friday 26 Aug 2016
[new Date(), new Date(2016,7,26)].forEach(function(d) {
  console.log(d.toLocaleString() + ' : ' + getNextBusinessDay(d).toLocaleString());
});

You can also test the day and add extra to get over the weekend:

// Classic Mon to Fri
function getNextWorkDay(date) {
  let d = new Date(+date);
  let day = d.getDay() || 7;
  d.setDate(d.getDate() + (day > 4? 8 - day : 1));
  return d;
}

for (let i=0, d=new Date(); i<7; i++) {
  console.log(`${d.toDateString()} -> ${getNextWorkDay(d).toDateString()}`);
  d.setDate(d.getDate() + 1);
}

Here is another approach where the work week can be specified using ECMAScript weekday numbers (Sun = 0, Mon = 1, etc.). Dates outside the range are shifted to the start of the next work week.

This is useful where the week is not the classic Mon to Fri, such as the Middle East where Sat to Wed is common or for some who might work Fri to Mon (or whatever).

function getNext(start, end, date) {
  let d = new Date(+date);
  d.setDate(d.getDate() + 1);
  let day = d.getDay();

  // Adjust end and day if necessary
  // The order of tests and adjustment is important
  if (end < start) {
    if (day <= end) {
      day += 7;
    }
    end += 7;
  }

  // If day is before start, shift to start
  if (day < start) {
    d.setDate(d.getDate() + start - day);

    // If day is after end, shift to next start (treat Sunday as 7)
  } else if (day > end) {
    d.setDate(d.getDate() + 8 - (day || 7));
  }
  return d;
}

// Examples
let f = new Intl.DateTimeFormat('en-GB', {
  weekday:'short',day:'2-digit', month:'short'});
let d = new Date();

[{c:'Work days Mon to Fri',s:1,e:5},
 {c:'Work days Sat to Wed',s:6,e:3},
 {c:'Work days Fri to Mon',s:5,e:1}
].forEach(({c,s,e}) => {
  for (let i = 0; i < 7; i++) {
    !i? console.log(`\n${c}`) : null;
    console.log(`${f.format(d)} => ${f.format(getNext(s, e, d))}`);
    d.setDate(d.getDate() + 1);
  }
});
Sorcha answered 25/8, 2016 at 6:23 Comment(2)
Actually your comment seemed even a better idea :)Zinciferous
@mplungjan—fixerated, :-)Sorcha
F
1

Attempting in two lines:

do date.setDate(date.getDate() + 1);
while ([0, 6].includes(date.getDay()));
Ferroconcrete answered 11/9 at 16:40 Comment(0)
C
0

Check this out: https://jsfiddle.net/e9a4066r/

function get_next_weekday (date) {
    var tomorrow = new Date(date.setDate(date.getDate() + 1))
    return tomorrow.getDay() % 6
        ? tomorrow
        : get_next_weekday(tomorrow)
}
Cording answered 25/8, 2016 at 8:21 Comment(2)
This is a beautiful way to do it! Code just has some issues. One example: If we use Dec 31, 2016 date jumps to Feb 02 instead of Jan 02, 2017 - Need to handle boundaries for months and years.Theorize
This is really just using recursion to iterate over weekends as for one of the other answers and it modifies the input Date. Recursion is typically less efficient than sequential processing.Sorcha
C
0

The accepted answer will skip one day at a time, which answers the OPs question, but for anyone looking to add a variable number of days while still skipping weekends the function below may be helpful:

function addWorkDays(date, days) {   
  while (days > 0) {
    date.setDate(date.getDate() + 1);
    if (date.getDay() != 0 && date.getDay() != 6) {
      days -= 1;
    }
  }          
  return date;
}
Counterweigh answered 6/2, 2018 at 19:17 Comment(1)
Has a problem with new year (31 Dec -> 1 Feb)Abdomen
N
0

Thought I'd throw my hat in the ring here with:

function getNextBusinessDate(date) {
  // Create date array [S, M, T, W, T, F, S]
  const days = new Array(7);
  let nextDate = date;
  for(let i = 0; i < 7; i++) {
    days[nextDate.getDay()] = new Date(nextDate);
    nextDate.setDate(nextDate.getDate() + 1);
  }

  // Shift indices to index as though array was [M, T, W, T, F, S, S]
  // Then truncate with min to make F, S, S all yield M for next date
  return days[Math.min((date.getDay() + 6) % 7 + 1, 5) % 5 + 1];
}
Nympho answered 16/2, 2022 at 21:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.