issue with getting special day [duplicate] - javascript

I have an date, i need to add no. of days to get future date but weekends should be excluded.
i.e
input date = "9-DEC-2011";
No. of days to add = '13';
next date should be "28-Dec-2011"
Here weekends(sat/sun) are not counted.

Try this
var startDate = "9-DEC-2011";
startDate = new Date(startDate.replace(/-/g, "/"));
var endDate = "", noOfDaysToAdd = 13, count = 0;
while(count < noOfDaysToAdd){
endDate = new Date(startDate.setDate(startDate.getDate() + 1));
if(endDate.getDay() != 0 && endDate.getDay() != 6){
//Date.getDay() gives weekday starting from 0(Sunday) to 6(Saturday)
count++;
}
}
alert(endDate);//You can format this date as per your requirement
Working Demo

#ShankarSangoli
Here's a newer version which avoid recreating a Date object on each loop, note that it's wrapped in a function now.
function calcWorkingDays(fromDate, days) {
var count = 0;
while (count < days) {
fromDate.setDate(fromDate.getDate() + 1);
if (fromDate.getDay() != 0 && fromDate.getDay() != 6) // Skip weekends
count++;
}
return fromDate;
}
alert(calcWorkingDays(new Date("9/DEC/2011"), 13));

Here is an elegant solution without any looping or external library:
function addBusinessDaysToDate(date, days) {
var day = date.getDay();
date = new Date(date.getTime());
date.setDate(date.getDate() + days + (day === 6 ? 2 : +!day) + (Math.floor((days - 1 + (day % 6 || 1)) / 5) * 2));
return date;
}
var date = "9-DEC-2011";
var newDate = addBusinessDaysToDate(new Date(date.replace(/-/g, "/")), 13);
console.log(newDate.toString().replace(/\S+\s(\S+)\s(\d+)\s(\d+)\s.*/, '$2-$1-$3')); // alerts "28-Dec-2011"

or you can be like this
function addWeekdays(date, weekdays) {
var newDate = new Date(date.getTime());
var i = 0;
while (i < weekdays) {
newDate.setDate(newDate.getDate() + 1);
var day = newDate.getDay();
if (day > 1 && day < 7) {
i++;
}
}
return newDate;
}
var currentDate = new Date('10/31/2014');
var targetDate = addWeekdays(currentDate, 45);
alert(targetDate);

Using moment.js:
const DATE_FORMAT = 'D-MMM-YYYY';
const SUNDAY = 0; // moment day index
const SATURDAY = 6; // moment day index
const WEEKENDS = [SATURDAY, SUNDAY];
function addBusinessDays(stringDate, numberOfDays, dateFormat = DATE_FORMAT) {
const date = moment(stringDate, dateFormat);
let count = 0;
while (count < numberOfDays) {
date.add(1, 'day');
// Skip weekends
if (WEEKENDS.includes(date.day())) {
continue;
}
// Increment count
count++;
}
return date.format(dateFormat);
}
// Test cases
console.log(addBusinessDays('3-Mar-2021', 1)); // 4-Mar-2021
console.log(addBusinessDays('3-Mar-2021', 2)); // 5-Mar-2021
console.log(addBusinessDays('3-Mar-2021', 3)); // 8-Mar-2021
console.log(addBusinessDays('3-Mar-2021', 4)); // 9-Mar-2021
console.log(addBusinessDays('3-Mar-2021', 5)); // 10-Mar-2021
console.log(addBusinessDays('9-Dec-2011', 13)); // 28-Dec-2011
console.log(addBusinessDays('10-Dec-2011', 13)); // 28-Dec-2011 (Saturday, so remain on Friday)
console.log(addBusinessDays('11-Dec-2011', 13)); // 28-Dec-2011 (Sunday, so remain on Friday)
console.log(addBusinessDays('12-Dec-2011', 13)); // 29-Dec-2011
console.log(addBusinessDays('13-Dec-2011', 13)); // 30-Dec-2011
console.log(addBusinessDays('14-Dec-2011', 13)); // 2-Jan-2012
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>

This question is quite old, but all the previous answers are iterating over the days one by one. That could be inefficient for a large number of days. This works for me, assuming days is a positive int and the startDate is a working day:
function addWorkingDates(startDate, days) {
const current_day = startDate.getDay() - 1; // Week day, starting on Monday
const weekend_days = 2 * parseInt((current_day + days) / 5);
startDate.setDate(changed_to.getDate() + days + weekend_days);
}
addWorkingDates(new Date(),5)

For some reason it was more intuitive to me to try this recursively. This version doesn't account for holidays, but you could change the isValid function to check whatever.
function addWeekdaysToDate(date, numberToAdd) {
var isValid = function(d) { return d.getDay() !== 0 && d.getDay() !== 6 }
if(Math.abs(numberToAdd) > 1) {
return addWeekdaysToDate(
addWeekdaysToDate(date, Math.sign(numberToAdd)),
numberToAdd - Math.sign(numberToAdd)
)
} else if(Math.abs(numberToAdd) === 1) {
var result = new Date(date)
result.setDate(result.getDate() + Math.sign(numberToAdd))
if(isValid(result)) {
return result
} else {
return addWeekdaysToDate(result, Math.sign(numberToAdd))
}
} else if(numberToAdd === 0) {
return date
}
return false
}
console.log(addWeekdaysToDate(new Date(), 1))
console.log(addWeekdaysToDate(new Date(), 5))
console.log(addWeekdaysToDate(new Date(), -7))
In certain browsers you may need a polyfill for Math.sign:
Math.sign = Math.sign || function(x) {
x = +x; // convert to a number
if (x === 0 || isNaN(x)) {
return Number(x);
}
return x > 0 ? 1 : -1;
}

try this solution
<script language="javascript">
function getDateExcludeWeekends(startDay, startMonth, startYear, daysToAdd) {
var sdate = new Date();
var edate = new Date();
var dayMilliseconds = 1000 * 60 * 60 * 24;
sdate.setFullYear(startYear,startMonth,startDay);
edate.setFullYear(startYear,startMonth,startDay+daysToAdd);
var weekendDays = 0;
while (sdate <= edate) {
var day = sdate.getDay()
if (day == 0 || day == 6) {
weekendDays++;
}
sdate = new Date(+sdate + dayMilliseconds);
}
sdate.setFullYear(startYear,startMonth,startDay + weekendDays+daysToAdd);
return sdate;
}
</script>

If you want to get the next working day, from a specific date, use the following code...
function getNextWorkingDay(originalDate) {
var nextWorkingDayFound = false;
var nextWorkingDate = new Date();
var dateCounter = 1;
while (!nextWorkingDayFound) {
nextWorkingDate.setDate(originalDate.getDate() + dateCounter);
dateCounter++;
if (!isDateOnWeekend(nextWorkingDate)) {
nextWorkingDayFound = true;
}
}
return nextWorkingDate;
}
function isDateOnWeekend(date) {
if (date.getDay() === 6 || date.getDay() === 0)
return true;
else
return false;
}

Try this
function calculate() {
var noOfDaysToAdd = 13;
var startDate = "9-DEC-2011";
startDate = new Date(startDate.replace(/-/g, "/"));
var endDate = "";
count = 0;
while (count < noOfDaysToAdd) {
endDate = new Date(startDate.setDate(startDate.getDate() + 1));
if (endDate.getDay() != 0 && endDate.getDay() != 6) {
count++;
}
}
document.getElementById("result").innerHTML = endDate;
}
<div>
Date of book delivery: <span id="result"></span><br /><br />
<input type="button" onclick="calculate();" value="Calculate" />
<br>
<br>
</div>

Related

Date format change

I would like to change the date format in my code like that - > 19.7.2016
Could anyone help me, please?
function calcWorkingDays(fromDate, days) {
var count = 0;
var m = new Date();
while (count < days) {
fromDate.setDate(fromDate.getDate() + 1);
if (fromDate.getDay() != 0 && fromDate.getDay() != 6) // Skip weekends
count++;
}
return fromDate;
}
alert(calcWorkingDays(new Date(), 4));
You need to format the dateobject to your likeness:
Extract the Day, Month and Year from your DateObject:
var month = fromDate.getUTCMonth() + 1; //months from 1-12
//January=0, February=1, etc
var day = fromDate.getUTCDate();
var year = fromDate.getUTCFullYear();
newdate = day + "." + month + "." + year;
Complete Example:
function calcWorkingDays(fromDate, days) {
var count = 0;
var m = new Date();
while (count < days) {
fromDate.setDate(fromDate.getDate() + 1);
if (fromDate.getDay() != 0 && fromDate.getDay() != 6) // Skip weekends
count++;
}
var month = fromDate.getUTCMonth() + 1;
var day = fromDate.getUTCDate();
var year = fromDate.getUTCFullYear();
newdate = day + "." + month + "." + year;
return newdate;
}
alert(calcWorkingDays(new Date(), 4));
Other possible examples are:
new Date().toISOString()
"2016-02-18T23:59:48.039Z"
new Date().toISOString().split('T')[0];
"2016-02-18"
new Date().toISOString().replace('-', '/').split('T')[0].replace('-', '/');
"2016/02/18"
new Date().toLocaleString().split(',')[0]
"2/18/2016"
source
You should convert date to string:
function calcWorkingDays(fromDate, days) {
var count = 0;
var m = new Date();
while (count < days) {
fromDate.setDate(fromDate.getDate() + 1);
if (fromDate.getDay() != 0 && fromDate.getDay() != 6) // Skip weekends
count++;
}
return fromDate.getDate() + "." + (fromDate.getMonth()+1) + "." + fromDate.getFullYear();
}
alert(calcWorkingDays(new Date(), 4));

Get only number of working days between two days in javascript

I have to calculate variables in javascript after x days from current day.I have to add some number of days based on some input parameter.
var currentDate = new Date();
var dd = currentDate.getDate();
var mm = currentDate.getMonth()+1;
var yyyy = currentDate.getFullYear();
if(dd<10) {
dd='0'+dd
}
if(mm<10) {
mm='0'+mm
}
currentDate= mm+'/'+dd+'/'+yyyy;
Now I want to get some date after 28 days from currentDate variable but it should not include Saturday and Sunday.
So my question is how to exclude the weekends (2 days) from the 28 (for example).
Any help will be appreciated.
Here's a generic function to add n business days to a date
function addDays(dt, n) {
var rem = n % 5;
var add = 7 * (n - rem) / 5 + rem;
var ret = new Date(dt);
ret.setDate(ret.getDate() + add);
if (ret.getDay() == 6) ret.setDate(ret.getDate() + 2);
else if (ret.getDay() == 0) ret.setDate(ret.getDate() + 1);
return ret;
}
This is really simple. Script below goes through all days between start and end date and checks if it isn't Saturday (tmpDate.getDay() != 6) or Sunday (tmpDate.getDay() != 0)
var start = new Date();
var end = new Date(2016, 6, 1);
var allDays = Math.floor((end.getTime() - start.getTime())/ 86400000);
var workingDays = 0;
for(var i = 0; i < allDays; i++){
var tmpDate = new Date();
tmpDate.setTime(today.getTime() + i * 24*60*60*1000);
if(tmpDate.getDay() != 0 && tmpDate.getDay() != 6)
wokringDays++;
}
alert(workingDays);
This will give you the number of working days:
function getWorkingDays(currentDateObj, numberOfDays)
{
if(numberOfDays < 0) return false;
var futureDateObj = new Date();
futureDateObj.setDate(currentDateObj.getDate() + numberOfDays);
var daysCnt = 1 + Math.round((futureDateObj.getTime()-currentDateObj.getTime())/(24*3600*1000));
var weekCnt = Math.floor( (currentDateObj.getDay() + daysCnt) / 7 );
var weekends = 2 * weekCnt + (currentDateObj.getDay()==0) - (futureDateObj.getDay()==6);
return numberOfDays - weekends;
}
console.log(getWorkingDays(new Date(), 28));

First Tuesday of every Month

Hello I am trying to use the following code which is a mish mash of "lifted code" but it keeps pumping out todays date and time.
I am trying to get the date for the first Tuesday of every month at 19:00.
I am using W3C School Try-it for testing purposes.
<!DOCTYPE html>
<html>
<head>
<script>
function displayDate()
{
var myDate = new Date();
myDate.setHours(19, 00, 0, 0);
myDate.setYear(2013);
myDate.setDate(1);
myDate.setMonth();
//Find Tuesday
var tue = 2;
while(myDate.getDay() != tue) {
myDate.setDate(myDate.getDate() + 1);
}
document.write(myDate);
</script>
</head>
<body>
<h1>My First JavaScript</h1>
<p id="demo">This is a paragraph.</p>
<button type="button" onclick="displayDate()">Display Date</button>
</body>
</html>
Roy
<==Update==>
I have use your code which works well but need to factor in after the First Tuesday has happened for the next month, I have tried this if statement but breaks.
function getTuesday() {
var datenow = new Date();
var d = new Date(),
month = d.getMonth(),
tuedays= [];
d.setDate(1);
// Get the first Monday in the month
while (d.getDay() !== 2) {
d.setDate(d.getDate() + 1);
}
// Get all the other Tuesdays in the month
while (d.getMonth() === month) {
tuedays.push(new Date(d.setHours(17,00,00,00)));
d.setDate(d.getDate() + 7);
}
If (d.getDate() >= datenow.getDate)
{
d.setMonth(d.getMonth() + 1);
document.write(tuedays[1]);
}
Else
{
document.write(tuedays[1]);
}
}
Use below function, that will give you current month Tuesdays.
function getTuesday() {
var d = new Date(),
month = d.getMonth(),
tuesdays= [];
d.setDate(1);
// Get the first Monday in the month
while (d.getDay() !== 2) {
d.setDate(d.getDate() + 1);
}
// Get all the other Tuesdays in the month
while (d.getMonth() === month) {
tuesdays.push(new Date(d.getTime()));
d.setDate(d.getDate() + 7);
}
return tuesdays;
}
I know that this is old but this is a function that i wrote based on what Sahal wrote that accepts a few additional features. Ill go through the arguments and returns below.
function getDates(dayString, month, year, first, allInYear) {
if (!dayString) { console.error('Missing required parameter: dayString is required.'); return; }
if (first === undefined || first === null) { first = false; }
if (allInYear === undefined || allInYear === null) { allInYear = false; }
if (year === undefined || year === null) { year = new Date().getFullYear(); }
var converted = false;
if (month === undefined || month === null) {
var temp = new Date();
if (temp.getDate() > 9) {
month = ((temp.getMonth() + 1) == 12) ? 11 : (temp.getMonth() + 1);
} else {
month = temp.getMonth();
}
converted = true;
}
if (typeof month === "string" && isNaN(parseInt(month))) {
month = month.toLowerCase().substring(0, 3);
switch (month) {
case "jan":
month = 0;
break;
case "feb":
month = 1;
break;
case "mar":
month = 2;
break;
case "apr":
month = 3;
break;
case "may":
month = 4;
break;
case "jun":
month = 5;
break;
case "jul":
month = 6;
break;
case "aug":
month = 7;
break;
case "sep":
month = 8;
break;
case "oct":
month = 9;
break;
case "nov":
month = 10;
break;
case "dec":
month = 11;
break;
default:
var temp = new Date();
if (temp.getDate() > 9) {
month = ((temp.getMonth() + 1) == 12) ? 11 : (temp.getMonth() + 1);
} else {
month = temp.getMonth();
}
converted = true;
break;
}
} else if (typeof month === "number" || (typeof month === "string" && !isNaN(parseInt(month)))) {
month = (!converted) ? parseInt(month) - 1 : month;
}
if (typeof year === "string" && !isNaN(parseInt(year)) || typeof year === "number") {
if (parseInt(year) / 1000 > 2) {
year = parseInt(year);
} else if (parseInt(year) / 10 >= 0 && parseInt(year) / 10 < 10) {
var temp2 = new Date().getFullYear();
year = (parseInt(Math.floor(temp2 / 100)) * 100) + parseInt(year);
}
} else if (typeof year === "string" && isNaN(parseInt(year))) {
if (year === "this") {
year = new Date().getFullYear();
} else if (year === "last") {
year = new Date().getFullYear() - 1;
} else if (year === "next") {
year = new Date().getFullYear() + 1;
} else {
console.warn('Year string not recognized, falling back to current year. (this, last, next).');
year = new Date().getFullYear();
}
}
var dates = [];
//hang in there this is going to get a doosie
var d = new Date(),
dow = ["sun", "mon", "tue", "wed", "thu", "fri", "sat"],
getDow = function(sd, dowa) {
for (var i = 0; i < dowa.length; i++) {
var day = dowa[i];
if (sd.toLowerCase().substring(0, 3) == day) {
return i;
}
}
return -1;
},
di = getDow(dayString, dow),
getDIM = function(year, mon) {
var isLeap = ((year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0));
return [31, (isLeap ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][mon];
};
d.setFullYear(year);
d.setMonth(month, 1);
if (di == -1) { console.error('Range Error: Day of the week should be between sunday and saturday'); return; }
if (first && !allInYear) {
while (d.getDay() !== di) {
d.setDate(d.getDate() + 1);
}
return d;
} else if (first && allInYear) {
var tm = 0;
d.setMonth(tm, 1);
for (var i = tm; i <= 11; i++) {
while (d.getDay() !== di) {
d.setDate(d.getDate() + 1);
}
dates.push(new Date(d));
tm += 1;
d.setMonth(tm, 1);
}
return dates;
} else if (!first && !allInYear) {
var eom = getDIM(d.getFullYear(), d.getMonth());
for (var x = 1; x <= eom; x++) {
if (d.getDay() === di) {
dates.push(new Date(d));
}
d.setDate(d.getDate() + 1);
}
return dates;
} else if (!first && allInYear) {
var tm = 0;
for (var i = 0; i <= 11; i++) {
var eom = getDIM(d.getFullYear(), i),
dim = [];
d.setMonth(i, 1);
for (var x = 1; x <= eom && d.getMonth() == i; x++) {
if (d.getDay() === di) {
dim.push(new Date(d));
}
d.setDate(d.getDate() + 1);
}
dates.push(dim);
}
return dates;
} else {
return [];
}
}
So the only required argument is the day string, optionally you can set month,year,first or all in a month and all in a year or not, month and year default to current, and first and allInYear default to false, But you can set first in moth, by passing null or undefined to the month and year parameter.
month parameter accepts: null|undefined, number, or string eg 'July'
year parameter accepts: null|undefined, number 2 or 4 digit, string eg '19' or '2019' also 'last', 'this', 'next'
returns Date object,Array[Date object...], or Array[Array[Date object...]...]
This has been tested and should cover most situations...
Well, it's been over 8 years since I asked this question, and it showed up at the top result on Google for 'The first Tuesday of every month'. The original project is dead now, but I've gained more experience, I feel better placed to provide an answer.
First thing to note, is the original question wasn't obvious, and the title was just as ambiguous. The original goal, was to get the next occurrence of a first Tuesday of the month, so could be the current month, or next month depending on where you are in the month.
Because of the ambiguity in the question, I have tried to cover for those differences in interpretation in the answer.
My first function, is to get the occurrence of a specific day of the week for a given month and year. Thank you to #Amadan in the comments on one of the answers.
function GetFirstDayOfMonth(dayOfTheWeek, month, year){
const date = new Date(year, month, 1);
date.setDate(date.getDate() + ((7 + dayOfTheWeek) - date.getDay()) % 7)
return date;
}
The next function, gets the next occurrence of a first specified day of the week given a date.
function GetFirstNextFirstDayOfTheWeek(currentDate, day){
const returnValue = GetFirstDayOfMonth(day, currentDate.getMonth(), currentDate.getFullYear());
if(returnValue.getDate() < currentDate.getDate()){
return GetFirstNextFirstDayOfTheWeek(new Date(currentDate.getFullYear(), currentDate.getMonth() + 1), day);
}
return returnValue;
}
So to achieve the original question I can run the following example
const tuesday = 2;
function GetFirstNextFirstTuesday(){
return GetFirstNextFirstDayOfTheWeek(new Date(), tuesday);
}
To achieve getting the first Tuesday of a Month
const tuesday = 2;
function GetFirstTuesday(month, year){
return GetFirstDayOfMonth(tuesday, month, year);
}
And to finish getting all the first Tuesdays of a given year.
const tuesday = 2;
function GetFirstTuesdayOfEveryMonth(year){
const dates = [];
for (let index = 0; index < 12; index++) {
dates.push(GetFirstDayOfMonth(tuesday, index, year));
}
return dates;
}
function GetFirstDayOfMonth(dayOfTheWeek, month, year){
// Get the first day of the month
const date = new Date(year, month, 1);
// Set the date based on the day of the week.
date.setDate(date.getDate() + ((7 + dayOfTheWeek) - date.getDay()) % 7)
return date;
}
function GetFirstNextFirstDayOfTheWeek(currentDate, day){
const returnValue = GetFirstDayOfMonth(day, currentDate.getMonth(), currentDate.getFullYear());
if(returnValue.getDate() < currentDate.getDate()){
return GetFirstNextFirstDayOfTheWeek(new Date(currentDate.getFullYear(), currentDate.getMonth() + 1), day);
}
return returnValue;
}
const tuesday = 2;
function GetFirstTuesday(month, year){
return GetFirstDayOfMonth(tuesday, month, year);
}
function GetFirstNextFirstTuesday(){
return GetFirstNextFirstDayOfTheWeek(new Date(), tuesday);
}
function GetFirstTuesdayOfEveryMonth(year){
const dates = [];
for (let index = 0; index < 12; index++) {
dates.push(GetFirstDayOfMonth(tuesday, index, year));
}
return dates;
}
console.log(GetFirstNextFirstTuesday());
console.log(GetFirstTuesday(09, 2021));
console.log(GetFirstTuesdayOfEveryMonth(2022));
Hopefully, this can help anyone who may seem to stubble on this old post, and thank you to the people that did answer.

Add no. of days in a date to get next date(excluding weekends)

I have an date, i need to add no. of days to get future date but weekends should be excluded.
i.e
input date = "9-DEC-2011";
No. of days to add = '13';
next date should be "28-Dec-2011"
Here weekends(sat/sun) are not counted.
Try this
var startDate = "9-DEC-2011";
startDate = new Date(startDate.replace(/-/g, "/"));
var endDate = "", noOfDaysToAdd = 13, count = 0;
while(count < noOfDaysToAdd){
endDate = new Date(startDate.setDate(startDate.getDate() + 1));
if(endDate.getDay() != 0 && endDate.getDay() != 6){
//Date.getDay() gives weekday starting from 0(Sunday) to 6(Saturday)
count++;
}
}
alert(endDate);//You can format this date as per your requirement
Working Demo
#ShankarSangoli
Here's a newer version which avoid recreating a Date object on each loop, note that it's wrapped in a function now.
function calcWorkingDays(fromDate, days) {
var count = 0;
while (count < days) {
fromDate.setDate(fromDate.getDate() + 1);
if (fromDate.getDay() != 0 && fromDate.getDay() != 6) // Skip weekends
count++;
}
return fromDate;
}
alert(calcWorkingDays(new Date("9/DEC/2011"), 13));
Here is an elegant solution without any looping or external library:
function addBusinessDaysToDate(date, days) {
var day = date.getDay();
date = new Date(date.getTime());
date.setDate(date.getDate() + days + (day === 6 ? 2 : +!day) + (Math.floor((days - 1 + (day % 6 || 1)) / 5) * 2));
return date;
}
var date = "9-DEC-2011";
var newDate = addBusinessDaysToDate(new Date(date.replace(/-/g, "/")), 13);
console.log(newDate.toString().replace(/\S+\s(\S+)\s(\d+)\s(\d+)\s.*/, '$2-$1-$3')); // alerts "28-Dec-2011"
or you can be like this
function addWeekdays(date, weekdays) {
var newDate = new Date(date.getTime());
var i = 0;
while (i < weekdays) {
newDate.setDate(newDate.getDate() + 1);
var day = newDate.getDay();
if (day > 1 && day < 7) {
i++;
}
}
return newDate;
}
var currentDate = new Date('10/31/2014');
var targetDate = addWeekdays(currentDate, 45);
alert(targetDate);
Using moment.js:
const DATE_FORMAT = 'D-MMM-YYYY';
const SUNDAY = 0; // moment day index
const SATURDAY = 6; // moment day index
const WEEKENDS = [SATURDAY, SUNDAY];
function addBusinessDays(stringDate, numberOfDays, dateFormat = DATE_FORMAT) {
const date = moment(stringDate, dateFormat);
let count = 0;
while (count < numberOfDays) {
date.add(1, 'day');
// Skip weekends
if (WEEKENDS.includes(date.day())) {
continue;
}
// Increment count
count++;
}
return date.format(dateFormat);
}
// Test cases
console.log(addBusinessDays('3-Mar-2021', 1)); // 4-Mar-2021
console.log(addBusinessDays('3-Mar-2021', 2)); // 5-Mar-2021
console.log(addBusinessDays('3-Mar-2021', 3)); // 8-Mar-2021
console.log(addBusinessDays('3-Mar-2021', 4)); // 9-Mar-2021
console.log(addBusinessDays('3-Mar-2021', 5)); // 10-Mar-2021
console.log(addBusinessDays('9-Dec-2011', 13)); // 28-Dec-2011
console.log(addBusinessDays('10-Dec-2011', 13)); // 28-Dec-2011 (Saturday, so remain on Friday)
console.log(addBusinessDays('11-Dec-2011', 13)); // 28-Dec-2011 (Sunday, so remain on Friday)
console.log(addBusinessDays('12-Dec-2011', 13)); // 29-Dec-2011
console.log(addBusinessDays('13-Dec-2011', 13)); // 30-Dec-2011
console.log(addBusinessDays('14-Dec-2011', 13)); // 2-Jan-2012
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
This question is quite old, but all the previous answers are iterating over the days one by one. That could be inefficient for a large number of days. This works for me, assuming days is a positive int and the startDate is a working day:
function addWorkingDates(startDate, days) {
const current_day = startDate.getDay() - 1; // Week day, starting on Monday
const weekend_days = 2 * parseInt((current_day + days) / 5);
startDate.setDate(changed_to.getDate() + days + weekend_days);
}
addWorkingDates(new Date(),5)
For some reason it was more intuitive to me to try this recursively. This version doesn't account for holidays, but you could change the isValid function to check whatever.
function addWeekdaysToDate(date, numberToAdd) {
var isValid = function(d) { return d.getDay() !== 0 && d.getDay() !== 6 }
if(Math.abs(numberToAdd) > 1) {
return addWeekdaysToDate(
addWeekdaysToDate(date, Math.sign(numberToAdd)),
numberToAdd - Math.sign(numberToAdd)
)
} else if(Math.abs(numberToAdd) === 1) {
var result = new Date(date)
result.setDate(result.getDate() + Math.sign(numberToAdd))
if(isValid(result)) {
return result
} else {
return addWeekdaysToDate(result, Math.sign(numberToAdd))
}
} else if(numberToAdd === 0) {
return date
}
return false
}
console.log(addWeekdaysToDate(new Date(), 1))
console.log(addWeekdaysToDate(new Date(), 5))
console.log(addWeekdaysToDate(new Date(), -7))
In certain browsers you may need a polyfill for Math.sign:
Math.sign = Math.sign || function(x) {
x = +x; // convert to a number
if (x === 0 || isNaN(x)) {
return Number(x);
}
return x > 0 ? 1 : -1;
}
try this solution
<script language="javascript">
function getDateExcludeWeekends(startDay, startMonth, startYear, daysToAdd) {
var sdate = new Date();
var edate = new Date();
var dayMilliseconds = 1000 * 60 * 60 * 24;
sdate.setFullYear(startYear,startMonth,startDay);
edate.setFullYear(startYear,startMonth,startDay+daysToAdd);
var weekendDays = 0;
while (sdate <= edate) {
var day = sdate.getDay()
if (day == 0 || day == 6) {
weekendDays++;
}
sdate = new Date(+sdate + dayMilliseconds);
}
sdate.setFullYear(startYear,startMonth,startDay + weekendDays+daysToAdd);
return sdate;
}
</script>
If you want to get the next working day, from a specific date, use the following code...
function getNextWorkingDay(originalDate) {
var nextWorkingDayFound = false;
var nextWorkingDate = new Date();
var dateCounter = 1;
while (!nextWorkingDayFound) {
nextWorkingDate.setDate(originalDate.getDate() + dateCounter);
dateCounter++;
if (!isDateOnWeekend(nextWorkingDate)) {
nextWorkingDayFound = true;
}
}
return nextWorkingDate;
}
function isDateOnWeekend(date) {
if (date.getDay() === 6 || date.getDay() === 0)
return true;
else
return false;
}
Try this
function calculate() {
var noOfDaysToAdd = 13;
var startDate = "9-DEC-2011";
startDate = new Date(startDate.replace(/-/g, "/"));
var endDate = "";
count = 0;
while (count < noOfDaysToAdd) {
endDate = new Date(startDate.setDate(startDate.getDate() + 1));
if (endDate.getDay() != 0 && endDate.getDay() != 6) {
count++;
}
}
document.getElementById("result").innerHTML = endDate;
}
<div>
Date of book delivery: <span id="result"></span><br /><br />
<input type="button" onclick="calculate();" value="Calculate" />
<br>
<br>
</div>

add/subtract business days in Javascript

I need a Date.prototype.addBusDays function
that'll take an integer as the number of working days to add to the date.
However, there are two considerations: 1. Weekends, 2. Holidays (which I imagine would be a preset array to compare against. If beginning date and end date contain 3 holidays, then you push out the end date by 3)
I have come across some scripts online, one dilemma I can think of is, lets say you address all the weekends first, then you do the holidays, what if you +1 day (due to holiday), and your end date is pushed into a weekends again...<
Any ideas?
Thanks!
EDIT:
This is a part of a scheduling tool I am developing, which mean the dates will be tied to tasks which are linked together. Adding 1 day to a task, will trigger a recalculation of everything tied to it, potentially all dates in the database.
Datageek's solution helped me but I needed to augment it. This still doesn't do holidays but does do working days with the option of including Sat and/or Sun, and does support adding negative days:-
function AddWorkingDays(datStartDate, lngNumberOfWorkingDays, blnIncSat, blnIncSun) {
var intWorkingDays = 5;
var intNonWorkingDays = 2;
var intStartDay = datStartDate.getDay(); // 0=Sunday ... 6=Saturday
var intOffset;
var intModifier = 0;
if (blnIncSat) { intWorkingDays++; intNonWorkingDays--; }
if (blnIncSun) { intWorkingDays++; intNonWorkingDays--; }
var newDate = new Date(datStartDate)
if (lngNumberOfWorkingDays >= 0) {
// Moving Forward
if (!blnIncSat && blnIncSun) {
intOffset = intStartDay;
} else {
intOffset = intStartDay - 1;
}
// Special start Saturday rule for 5 day week
if (intStartDay == 6 && !blnIncSat && !blnIncSun) {
intOffset -= 6;
intModifier = 1;
}
} else {
// Moving Backward
if (blnIncSat && !blnIncSun) {
intOffset = intStartDay - 6;
} else {
intOffset = intStartDay - 5;
}
// Special start Sunday rule for 5 day week
if (intStartDay == 0 && !blnIncSat && !blnIncSun) {
intOffset++;
intModifier = 1;
}
}
// ~~ is used to achieve integer division for both positive and negative numbers
newDate.setTime(datStartDate.getTime() + (new Number((~~((lngNumberOfWorkingDays + intOffset) / intWorkingDays) * intNonWorkingDays) + lngNumberOfWorkingDays + intModifier)*86400000));
return newDate;
}
Have a look at the following implementation. Sourced from about.com
addWeekdays = function(date, dd) {
var wks = Math.floor(dd/5);
var dys = dd.mod(5);
var dy = this.getDay();
if (dy === 6 && dys > -1) {
if (dys === 0) {dys-=2; dy+=2;}
dys++; dy -= 6;
}
if (dy === 0 && dys < 1) {
if (dys === 0) {dys+=2; dy-=2;}
dys--; dy += 6;
}
if (dy + dys > 5) dys += 2;
if (dy + dys < 1) dys -= 2;
date.setDate(date.getDate()+wks*7+dys);
}
var date = new Date();
addWeekdays(date, 9);
(Updated) I've put this algorithm through its paces and it seems stable, though it does use recursion for holiday processing:
holidays = [new Date("2/13/2019"), new Date("2/19/2019")];
function addWorkdays(workdays, startDate) {
//Make adjustments if the start date is on a weekend
let dayOfWeek = startDate.getDay();
let adjustedWorkdays = Math.abs(workdays);
if (0 == dayOfWeek || 6 == dayOfWeek) {
adjustedWorkdays += (Math.abs((dayOfWeek % 5) + Math.sign(workdays)) % 2) + 1;
dayOfWeek = (dayOfWeek - 6) * -1;
}
let endDate = new Date(startDate);
endDate.setDate(endDate.getDate() + (((Math.floor(((workdays >= 0 ? dayOfWeek - 1 : 6 - dayOfWeek) + adjustedWorkdays) / 5) * 2) + adjustedWorkdays) * (workdays < 0 ? -1 : 1)));
//If we cross holidays, recompute our end date accordingly
let numHolidays = holidays.reduce(function(total, holiday) { return (holiday >= Math.min(startDate, endDate) && holiday <= Math.max(startDate, endDate)) ? total + 1 : total; }, 0);
if (numHolidays > 0) {
endDate.setDate(endDate.getDate() + Math.sign(workdays));
return addWorkdays((numHolidays - 1) * Math.sign(workdays), endDate);
} else return endDate;
}
I expanded on khellendros74's answer for a project of mine that needed to disable Sundays and mailing holidays in the datepicker and return two dates on press of a button: three business days (i.e. non-holiday and non-Sunday) after the date picked in the datepicker (a field with an id of "calendar") and six business days after the date picked in the datepicker and then put those two results into a couple of disabled input fields (handDelivered and mailed). The button press calls the function calculateDates. Here is that code:
var disabledDates = ['11/11/2015', '11/26/2015', '12/25/2015', '01/01/2016','01/18/2016', '02/15/2016','05/30/2016', '07/04/2016','09/05/2016','10/10/2016','11/11/2016','11/24/2016', '12/26/2016','01/02/2017','01/16/2017', '02/20/2017','05/29/2017', '07/04/2017','09/04/2017','10/09/2017','11/10/2017','11/23/2017', '12/25/2017','01/01/2018','01/15/2018', '02/19/2018','05/28/2018', '07/04/2018','09/03/2018','10/08/2018','11/12/2018','11/22/2018', '12/25/2018','01/01/2019','01/21/2019', '02/18/2019','05/27/2019', '07/04/2019','09/02/2019','10/14/2019','11/11/2019','11/28/2019', '12/25/2019','01/01/2020','01/20/2020', '02/17/2020','05/25/2020', '07/03/2020','09/07/2020','10/11/2020','11/26/2020','11/26/2020', '12/25/2020'];
$(function(){
$('#calendar').datepicker({
dateFormat: 'mm/dd/yy',
beforeShowDay: editDays
});
function editDays(date) {
for (var i = 0; i < disabledDates.length; i++) {
if (new Date(disabledDates[i]).toString() == date.toString() || date.getDay() == 0) {
return [false];
}
}
return [true];
}
});
function calculateDates()
{
if( !$('#calendar').val()){
alert("Please enter a date.");
document.getElementById('calendar').focus();
return false;
}
var dayThreeAdd = 0;
var daySixAdd = 0;
for (var i = 0; i < disabledDates.length; i++) {
var oneDays = AddWorkingDays($('#calendar').val(),1,true,false);
var twoDays = AddWorkingDays($('#calendar').val(),2,true,false);
var threeDays = AddWorkingDays($('#calendar').val(),3,true,false);
var fourDays = AddWorkingDays($('#calendar').val(),4,true,false);
var fiveDays = AddWorkingDays($('#calendar').val(),5,true,false);
var sixDays = AddWorkingDays($('#calendar').val(),6,true,false);
if (new Date(disabledDates[i]).toString() == oneDays.toString()) {
dayThreeAdd++;
daySixAdd++;
}
if (new Date(disabledDates[i]).toString() == twoDays.toString()) {
dayThreeAdd++;
daySixAdd++;
}
if (new Date(disabledDates[i]).toString() == threeDays.toString()) {
dayThreeAdd++;
daySixAdd++;
}
if (new Date(disabledDates[i]).toString() == fourDays.toString()) {
daySixAdd++;
}
if (new Date(disabledDates[i]).toString() == fiveDays.toString()) {
daySixAdd++;
}
if (new Date(disabledDates[i]).toString() == sixDays.toString()) {
daySixAdd++;
}
}
var threeDays = AddWorkingDays($('#calendar').val(),(3 + dayThreeAdd),true,false);
var sixDays = AddWorkingDays($('#calendar').val(),(6 + daySixAdd),true,false);
$('#handDelivered').val((threeDays.getMonth()+1) + '/' + threeDays.getDate() + '/' + (threeDays.getYear()+1900));
$('#mailed').val((sixDays.getMonth()+1) + '/' + sixDays.getDate() + '/' + (sixDays.getYear()+1900));
}
function AddWorkingDays(datStartDate, lngNumberOfWorkingDays, blnIncSat, blnIncSun) {
datStartDate = new Date(datStartDate);
var intWorkingDays = 5;
var intNonWorkingDays = 2;
var intStartDay = datStartDate.getDay(); // 0=Sunday ... 6=Saturday
var intOffset;
var intModifier = 0;
if (blnIncSat) { intWorkingDays++; intNonWorkingDays--; }
if (blnIncSun) { intWorkingDays++; intNonWorkingDays--; }
var newDate = new Date(datStartDate)
if (lngNumberOfWorkingDays >= 0) {
// Moving Forward
if (!blnIncSat && blnIncSun) {
intOffset = intStartDay;
} else {
intOffset = intStartDay - 1;
}
// Special start Saturday rule for 5 day week
if (intStartDay == 6 && !blnIncSat && !blnIncSun) {
intOffset -= 6;
intModifier = 1;
}
} else {
// Moving Backward
if (blnIncSat && !blnIncSun) {
intOffset = intStartDay - 6;
} else {
intOffset = intStartDay - 5;
}
// Special start Sunday rule for 5 day week
if (intStartDay == 0 && !blnIncSat && !blnIncSun) {
intOffset++;
intModifier = 1;
}
}
// ~~ is used to achieve integer division for both positive and negative numbers
newDate.setTime(datStartDate.getTime() + (new Number((~~((lngNumberOfWorkingDays + intOffset) / intWorkingDays) * intNonWorkingDays) + lngNumberOfWorkingDays + intModifier)*86400000));
return newDate;
}
Simple solution to solve the whole problem; you can just loop through the days to skip weekdays and holidays:
Date.prototype.holidays = {
// fill in common holidays
all: [
'0101', // Jan 01
'1225' // Dec 25
],
2016: [
// add year specific holidays
'0104' // Jan 04 2016
],
2017: [
// And so on for other years.
]
};
Date.prototype.addWorkingDays = function(days) {
while (days > 0) {
this.setDate(this.getDate() + 1);
if (!this.isHoliday()) days--;
}
return this;
};
Date.prototype.substractWorkingDays = function(days) {
while (days > 0) {
this.setDate(this.getDate() - 1);
if (!this.isHoliday()) days--;
}
return this;
};
Date.prototype.isHoliday = function() {
function zeroPad(n) {
n |= 0;
return (n < 10 ? '0' : '') + n;
}
// if weekend return true from here it self;
if (this.getDay() == 0 || this.getDay() == 6) {
return true;
}
var day = zeroPad(this.getMonth() + 1) + zeroPad(this.getDate());
// if date is present in the holiday list return true;
return !!~this.holidays.all.indexOf(day) ||
(this.holidays[this.getFullYear()] ?
!!~this.holidays[this.getFullYear()].indexOf(day) : false);
};
// Uasage
var date = new Date('2015-12-31');
date.addWorkingDays(10);
alert(date.toDateString()); // Mon Jan 18 2016
date.substractWorkingDays(10);
alert(date.toDateString()) // Thu Dec 31 2015
This only takes weekends into account and not holidays, but it's a start...
function mod(x, y) {
// https://stackoverflow.com/a/4467559/2173455
return ((x % y) + y) % y;
}
function calculateDateDiff(date, diff) {
let returnDate = new Date(date.getTime());
let daysLeftToAdd = Math.abs(diff);
let weekendDays = 0;
let weekDay = returnDate.getDay();
while(daysLeftToAdd >= 0) {
if(weekDay == 0 || weekDay == 6) {
weekendDays++;
}
else {
daysLeftToAdd--;
}
weekDay = mod(diff > 0 ? weekDay + 1 : weekDay - 1, 7);
}
returnDate.setDate(diff > 0 ?
returnDate.getDate() + diff + weekendDays :
returnDate.getDate() + diff - weekendDays
);
return returnDate;
}

Categories