Add Working Days to a Date Using JavaScript
Asked Answered
C

8

22

How can I use JavaScript to add working days (i.e. Mon - Friday) automatically adding weekends where necessary?

So if I were to add 5 working days to today (Tue. 22nd Nov. 2016) the result should be "Tue. 29th Nov. 2016" and not "Sun. 27th Nov. 2016".

Clotildecloture answered 22/11, 2016 at 10:11 Comment(0)
C
30

It is possible to use Date's setDate function (in combination with getDate) to add days onto a date i.e. -

var myDate = new Date(); // Tue 22/11/2016
myDate.setDate(myDate.getDate() + 3); // Fri 25/11/2016

So once you've calculated the number of weekend days within the workdays period you can add that and the required number of workdays to the start date to get the final date.

This function should work though obviously this will not take account of national holidays -

function addWorkDays(startDate, days) {
    if(isNaN(days)) {
        console.log("Value provided for \"days\" was not a number");
        return
    }
    if(!(startDate instanceof Date)) {
        console.log("Value provided for \"startDate\" was not a Date object");
        return
    }
    // Get the day of the week as a number (0 = Sunday, 1 = Monday, .... 6 = Saturday)
    var dow = startDate.getDay();
    var daysToAdd = parseInt(days);
    // If the current day is Sunday add one day
    if (dow == 0)
        daysToAdd++;
    // If the start date plus the additional days falls on or after the closest Saturday calculate weekends
    if (dow + daysToAdd >= 6) {
        //Subtract days in current working week from work days
        var remainingWorkDays = daysToAdd - (5 - dow);
        //Add current working week's weekend
        daysToAdd += 2;
        if (remainingWorkDays > 5) {
            //Add two days for each working week by calculating how many weeks are included
            daysToAdd += 2 * Math.floor(remainingWorkDays / 5);
            //Exclude final weekend if remainingWorkDays resolves to an exact number of weeks
            if (remainingWorkDays % 5 == 0)
                daysToAdd -= 2;
        }
    }
    startDate.setDate(startDate.getDate() + daysToAdd);
    return startDate;
}

//And use it like so (months are zero based)
var today = new Date(2016, 10, 22);
today = addWorkDays(today, 5); // Tue Nov 29 2016 00:00:00 GMT+0000 (GMT Standard Time)

It could also be added to the Date prototype -

Date.prototype.addWorkDays = function (days) {
    if(isNaN(days)) {
        console.log("Value provided for \"days\" was not a number");
        return
    }

    // Get the day of the week as a number (0 = Sunday, 1 = Monday, .... 6 = Saturday)
    var dow = this.getDay();
    var daysToAdd = parseInt(days);
    // If the current day is Sunday add one day
    if (dow == 0) {
        daysToAdd++;
    }
    // If the start date plus the additional days falls on or after the closest Saturday calculate weekends
    if (dow + daysToAdd >= 6) {
        //Subtract days in current working week from work days
        var remainingWorkDays = daysToAdd - (5 - dow);
        //Add current working week's weekend
        daysToAdd += 2;
        if (remainingWorkDays > 5) {
            //Add two days for each working week by calculating how many weeks are included
            daysToAdd += 2 * Math.floor(remainingWorkDays / 5);
            //Exclude final weekend if the remainingWorkDays resolves to an exact number of weeks
            if (remainingWorkDays % 5 == 0)
                daysToAdd -= 2;
        }
    }
    this.setDate(this.getDate() + daysToAdd);
};

//And use it like so (months are zero based)
var today = new Date(2016, 10, 22)
today.addWorkDays(5); // Tue Nov 29 2016 00:00:00 GMT+0000 (GMT Standard Time)
Clotildecloture answered 22/11, 2016 at 10:11 Comment(8)
For the prototype, instead of this.setDate(this.getDate() + daysToAdd);, I used return this.addDays(daysToAdd); because it more closely resembles the way the native Date.prototype.addDays works.Barbur
@Barbur native Date.prototype.addDays? I'm not aware of a native addDays method and it's not documented on MDN - developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…; are you sure it hasn't been added by another JS file in your solution?Clotildecloture
I stand corrected, it isn't native. In my case it was coming from the Kendo UI library. I wish it were native.Barbur
@MohsenAlyafei Are you able to provide example start date and days to add along with your expected result?Clotildecloture
@JohnC I withdraw my comment. In fact, I was testing your code in comparison with other numbers for the weekend (Fri and Sat) instead of (Sat and Sun).Pyorrhea
@JohnC Adding one (1) working day to 02-Dec-2023 (which is a Saturday) should give Monday 04-Dec-2023. It now gives Tue 05-Dec-2023Pyorrhea
@JohnC this seems to happen when the starting date falls on a weekend. Also negative numbers fail.Pyorrhea
@JohnC see the new post with a simpler solution that gives the same results as MS Excel WORKDAY functions for both positive and negative workdays to be added (subtracted) from a given date and its options for different locales. Hope it adds a contribution.Pyorrhea
I
4

If it's for adding a few days, not thousands of days, then this is easier and more readable:

const currentDate = new Date('2021-11-18');
console.log(currentDate.toString()); // "Thu Nov 18 2021 00:00:00 GMT+0000"

const numToAdd = 5;

for (let i = 1; i <= numToAdd; i++) {
  currentDate.setDate(currentDate.getDate() + 1);
  if (currentDate.getDay() === 6) {
    currentDate.setDate(currentDate.getDate() + 2);
  }
  else if (currentDate.getDay() === 0) {
    currentDate.setDate(currentDate.getDate() + 1);
  }
}

console.log(currentDate.toString()); // "Thu Nov 25 2021 00:00:00 GMT+0000"
Isoleucine answered 8/4, 2021 at 10:8 Comment(2)
I think this is the best solution, it's much more straight-forward and easier to understand. I edited your code slightly, Mark, hope that's okay.Ir
@MattFletcher in a similar concept but coded differently, see my solution here. Hope it can be of help: #40739559Pyorrhea
V
3

I think you can use moment-business-days.

Example:

// 22-11-2016 is Tuesday, DD-MM-YYYY is the format 
moment('22-11-2016', 'DD-MM-YYYY').businessAdd(5)._d // Tue Nov 29 2016 00:00:00 GMT-0600 (CST) 
Vitta answered 22/11, 2016 at 10:51 Comment(0)
C
2

const date = new Date('2000-02-02')
const daysToAdd = mapToWorkdays(date, 37)

date.setUTCDate(date.getUTCDate() + daysToAdd)

console.log( date.toISOString().split('T')[0] )
// prints 2000-03-24

/**
 * @param {Date} date starting date
 * @param {number} add number of workdays to add
 * @return {number} total number of days to add to reach correct date
 */
function mapToWorkdays(date, add) {
  const wd = weekday(date)
  
  let r = Math.trunc(add / 5) * 2
  const rem = add % 5

  if (wd > 4) r += (6-wd)
  else if (wd+rem > 4) r += 2

  return add + r
}

/**
 * @param {Date} date
 * @return {number} day of the week in range of 0..6 (monday..sunday)
 */
function weekday(date) { return (date.getUTCDay()+ 6) % 7 }
Cinch answered 20/4, 2018 at 10:23 Comment(1)
@Roebie I think the only issue is that it should be r += (7 - wd). If you call the function from sat/sun and pass add:0 the result should still return 2 for saturday, and 1 for sunday. The first if is actually saying: "If we're on weekends, adjust everything to first of the week (a.k.a 0)". and else-if says: "If we're on weekdays, and with add%5 we'll end-up in weekend, we should add two more days"Arlin
C
1

Updated above script to also subtract workdays if negative days are given...

function addWorkDays(startDate, days) {
    var isAddingDays = (days > 0);
    var isDaysToAddMoreThanWeek = (days > 5 || days < -5);

    if (isNaN(days)) {
        console.log("Value provided for \"days\" was not a number");
        return
    }
    if (!(startDate instanceof Date)) {
        console.log("Value provided for \"startDate\" was not a Date object");
        return
    }
    var dow = startDate.getDay();
    var daysToAdd = parseInt(days);

    if ((dow === 0 && isAddingDays) || (dow === 6 && !isAddingDays)) {
        daysToAdd = daysToAdd + (1 * (isAddingDays ? 1 : -1));
    } else if ((dow === 6 && isAddingDays) || (dow === 0 && !isAddingDays)) {
        daysToAdd = daysToAdd + (2 * (isAddingDays ? 1 : -1));
    }

    if (isDaysToAddMoreThanWeek) {
        daysToAdd = daysToAdd + (2 * (Math.floor(days / 5)));

        if (days % 5 != 0)
            daysToAdd = daysToAdd + (2 * (isAddingDays ?  -1 : 1));
    }

    startDate.setDate(startDate.getDate() + daysToAdd);
    var newDate = moment(startDate).format('MM/DD/YYYY');
    return newDate;
}
Chimere answered 23/1, 2020 at 15:54 Comment(1)
Doesn't work when starting from a Tuesday and adding 5 days (it returns the following Sunday).Kurtis
S
1

This is my simplyest final solution for me:

function addWorkDays(startDate, daysToAdd) {
  let dw=startDate.getDay(); //* see note
  startDate.setDate(startDate.getDate()-((dw==6)?1:(dw==0)?2:0)); //*
  var avance = 2 * Math.floor(daysToAdd / 5); //add 2 days for each 5 workdays
  var exceso = (daysToAdd % 5) + startDate.getDay() ;
  if (exceso>=6) avance +=2 ; 
  startDate.setDate(startDate.getDate() + daysToAdd + avance);
  return startDate;
}

// If used only with business day dates, the first two lines are not required
Schleicher answered 26/7, 2022 at 11:45 Comment(3)
Doesn't handle Sat & Sundays well. If you do +1 work day on Friday it gives you Monday on Saturday it gives you Tuesday and on Sunday it gives you MondayBluefish
Hello, ScrapHead. In order to be short, this code worked on business days. If you want it to work on holidays as well, just add something else at the beginning. I have completed the code for this case.Schleicher
This solution will not work with negative days (i.e. subtracting workdays from a date).Pyorrhea
M
1

An even simpler solution in pure JS using an array to know how many days to add to the current day of the week. Sunday is the first element in the array and you add 5 business days to get Friday. The weekdays all add 7 days to come up with the same day next week. Saturday adds 6 days to come up with Friday.

const daysToAddForFiveBusinessDays = [5,7,7,7,7,7,6]
function date5BusinessDays (startDate) {
    return new Date(startDate.setDate(startDate.getDate() + daysToAddForFiveBusinessDays [startDate.getDay()]));
}

I am going to use this style to find 3 working days in the future, and that code is listed below. For Sunday Monday and Tuesday you just add 3 business days, on Wednesday through Friday you add 5 days to get 3 business days, and on Saturday you need to add 4 days to get 3 business days.

const daysToAddForThreeBusinessDays = [3,3,3,5,5,5,4]
function date3BusinessDays(startDate) {
    return new Date(startDate.setDate(startDate.getDate() + daysToAddForThreeBusinessDays[startDate.getDay()]));
}

const daysToAddForFiveBusinessDays = [5,7,7,7,7,7,6]
const daysToAddForThreeBusinessDays = [3,3,3,5,5,5,4]

function fiveBusinessDaysFrom (startDate) {
    return new Date(startDate.setDate(startDate.getDate() + daysToAddForFiveBusinessDays [startDate.getDay()]));
}

function threeBusinessDaysFrom(startDate) {
    return new Date(startDate.setDate(startDate.getDate() + daysToAddForThreeBusinessDays[startDate.getDay()]));
}

console.log("five business days from today is " + fiveBusinessDaysFrom(new Date()))
console.log("three business days from today is " + threeBusinessDaysFrom(new Date()))
Muzz answered 12/7, 2023 at 20:33 Comment(9)
could you give an example function or code that works as you stated.Pyorrhea
How can do that for adding an arbitrary number of business days?Pyorrhea
@MohsenAlyafei it would not be an appropriate solution for arbitrary number of days not known at the time of developmentMuzz
For example take 22 working days; how will that work? Do we have to write a specific function for each number of days? As we do not know what the user input work days are nor the start date.Pyorrhea
@MohsenAlyafei yes this solution is for a specific number of days. It gets unweildy for larger numbers of days but it will work. The 22nd work day after Sunday is 30 calendar days later on a Tuesday. The 22nd work day after Monday is 30 days later on a Wednesday. Starting on Tuesday and Wednesay are the same 30 days. The 22nd work day from a Thursday would be 32 days later on a Monday. The 22nd work day from a Friday would be 32 days later on a tuesday. Your array of days starting from Sun, Mon, Tues Wed Thurs Fri, Sat looks like [30, 30, 30, 30, 32, 32]Muzz
Thanks a lot for your feedback. I will try to think of a simple solution and will post my findings if they work.Pyorrhea
Your idea answer deserves a vote upPyorrhea
Oops I left Saturday out of the 22 day example. 22 business days from any Saturday is 32 calendar days later on a Wednesday. The correct array should have been [30, 30, 30, 30, 32, 32, 32]Muzz
See simple solution as latest post here: #40739559Pyorrhea
P
1

Update Dec 2023

In general, there can be 2 methods to add working (business) days to a particular date:

Method 1. Workdays to Calendar Days Conversion

Under this method, the working days to be added are first converted to calendar days based on 2 additional days (i.e. weekend days) for every 5 working days. The resulting calendar days are then added to the date to arrive at the working date.

This assumes 2 weekend days per week that are consecutive (i.e. Sat & Sun, Fri & Sat, or Thu & Fri).

This method is not as simple as Method 2 (see below) for subtraction, adapting to other locales' weekends, using non-consecutive weekend days, or excluding holiday days.

The code will also need to cater for starting dates and resulting dates falling on weekends and corrections be made for that. This will increase code complexity for negative days count and for weekends that are non-consecutive days (such as weekends that are Friday and Sunday but not Saturday).

Method 2. Using a loop to skip weekend days (a for or while loop)

This method is simple, clean, easy to understand, and permits easy adaption for the following:

  1. Subtracting workdays from the given date.
  2. Non-consecutive weekend days.
  3. Simple implementation of other locales weekends (either 2 or 1 day weekends).
  4. Simple adaption to exclude holiday days. This is because each date is tested for being a weekend or not.

But Method 2 will be slower than Method 1?

In real-life use, the number of work days to be added to (or subtracted from) a particular date will not be hundreds of thousands or millions of work days.

A full year has 261 working days (assuming 2 days weekend) or 313 days assuming a 1 day weekend.

In practise, you will not need to add such a large number of work days !!

Some practical examples would be:

  1. Find the working days of a calendar year.
  2. Generate a calendar for a year with work days.
  3. Calculate the workdays for salary payments.

The above examples would need to only work with 100's of workdays and not millions of days.

In its basic form for adding work days, Method 2 is a one-line code using a while loop.

while (days) ![6,0].includes(date.getUTCDay(date.setUTCDate(date.getUTCDate()+1))) && days--;

The while loop works as follows:

//    1. let days => to be workdays to be added
//    2. let date => to be the start date
//    3. start while loop
// |->4. if days==0 return date [exit]
// |  5. get next date (date +=1)
// |  6. is the day a weekend? (day number in the array?)
// |  7. if not a weekend decrement days (days--)
// |<-8. loop again (step 4)

Notwithstanding the above, even if adding (say) 100 years’ worth of work days which is 261 x 100 = 26,100 work days using Method 2 as shown in the example below takes on average less than 15 milliseconds.

Here is an example with a test to add over 26,000 work days (100 years) !! with the resulting approximate execution time.

function addWorkDays(date, days) {
while (days) ![6,0].includes(date.getUTCDay(date.setUTCDate(date.getUTCDate()+1))) && days--;
return date;
}

//========= Test to add 100 years of working days ==========
let workdays = 261*100;  // 100 years of working days !!
const t0 = performance.now();
console.log(addWorkDays(new Date("2023-12-03"),workdays));  // date => 2123-12-17
const t1 = performance.now();
console.log(`Adding 100 years of work days took ${(t1-t0).toFixed(2)} milliseconds.`);

The above function assumes that weekend days are Saturday and Sunday days [6,0].

You can change that (the numbers in the array) to other weekend days say Friday and Saturday [5,6] as used in the Middle East and North Africa or just a one-day weekend like Sunday [0] as used in India, Philippines, etc.

Subtracting Work Days from a Date

The above simple one-line function cannot “subtract” workdays from a given date.

To do that we add the following 2 lines:

 let dir  = days<0?-1:1;  // if negative days then decrement
 days = Math.abs(days);   // days always positive integer

So, if the number of days is negative, instead of increasing the date by 1 (the next day), we use the variable dir which is -1 to decrease the date (previous day).

The revised function to add and subtract working dates from a date becomes:

function addWorkDays(date, days) {
let dir  = days<0?-1:1;
    days = Math.abs(days);
while (days) ![6,0].includes(date.getUTCDay(date.setUTCDate(date.getUTCDate()+dir))) && days--;
return date;
}

//===== test examples ====
console.log(addWorkDays(new Date("2023-12-03"),-10));   // 2023-11-20
console.log(addWorkDays(new Date("2023-12-03"),-20));   // 2023-11-06

Create a function that mimics MS Excel WORKDAY.INTL to add and subtract workdays for different locales

The above function can be improved by making it cater for weekends of different locales (other countries) so that it can mimic and produce the same results as used by MS Excel WORDAY and WORKDAY.INTL functions.

We can do that by passing the weekends as a parameter to the function either as an array of weekend days, or by finding the weekend information from the Intl.Locale constructor or by allowing both ways.

As the Intl.Locale(locale).weekInfo.weekend returns Sunday as day number 7 rather than 0, we will need to correct for that by changing 7 to 0 (if any) so that the getDay() method of Date understands it.

The short function below can now handle the addition and subtraction of workdays as well as handling other locales’ weekends.

The function now can accept other weekend locales (default is en-US, i.e. Sat and Sun).

Locales can be passed either as locale identifier strings (like 'en-US') or as an array of weekend days (like [4,5]).

The output produced will be identical to that produced by MS Excel WORDAY and WORKDAY.INTL functions, and it is fast.

function addWorkDays(date, days, locale="en-US") {
date=new Date(date);               // allow date to be given as ISO string
let w = Array.isArray(locale)?locale:new Intl.Locale(locale).weekInfo.weekend,
 dir  = days<0?-1:1;               // if negative days then decrement
 days = Math.abs(days);            // days always positive integer
 w.at(-1)==7 && (w[w.length-1]=0); // correct Sunday day from 7 to 0
while (days) !w.includes(date.getUTCDay(date.setUTCDate(date.getUTCDate()+dir))) && days--;
return date;
}

//======== test examples ========
console.log(addWorkDays("2023-12-03",10));          // 2023-12-15
console.log(addWorkDays("2023-12-03",10,"en-IN"));  // 2023-12-14
console.log(addWorkDays("2023-12-03",10,"ar-QA"));  // 2023-12-17
console.log(addWorkDays("2023-12-03",10,[5,6]));    // 2023-12-17
console.log(addWorkDays("2023-12-03",-10));         // 2023-11-20
console.log(addWorkDays("2023-12-03",-10,"en-IN")); // 2023-11-22
console.log(addWorkDays("2023-12-03",-10,"ar-QA")); // 2023-11-19
console.log(addWorkDays("2023-12-03",-10,[5,6]));   // 2023-11-19

Testing for Correct Results

The following tests have been confirmed with MS Excel WORKDAY.INTL function both for positive and negative days and with various locales. Using small and large workdays.

function addWorkDays(date, days, locale= "en-US") {
date=new Date(date);
let w = Array.isArray(locale)?locale:new Intl.Locale(locale).weekInfo.weekend,
 dir  = days<0?-1:1;
 days = Math.abs(days);
 w.at(-1)==7 && (w[w.length-1]=0);
while (days) !w.includes(date.getUTCDay(date.setUTCDate(date.getUTCDate()+dir))) && days--;
return date;
}

//=========================================
//             Test Cases
//=========================================

//========================================
// Test with Sat-Sun as weekend default
// uses locale 'en-US' for USA by default
//========================================

var r=0; // test tracker
r |=test(1,"2023-11-27",1,new Date("2023-11-28"));
r |=test(2,"2023-11-27",2,new Date("2023-11-29"));
r |=test(3,"2023-11-27",3,new Date("2023-11-30"));
r |=test(4,"2023-11-27",4,new Date("2023-12-01"));
r |=test(5,"2023-11-27",5,new Date("2023-12-04"));
r |=test(6,"2023-11-27",6,new Date("2023-12-05"));
r |=test(7,"2023-11-27",7,new Date("2023-12-06"));
r |=test(8,"2023-11-27",8,new Date("2023-12-07"));
r |=test(9,"2023-11-27",9,new Date("2023-12-08"));
r |=test(10,"2023-12-02",1,new Date("2023-12-04"));
r |=test(11,"2023-12-02",2,new Date("2023-12-05"));
r |=test(12,"2023-12-02",3,new Date("2023-12-06"));
r |=test(13,"2023-12-03",1,new Date("2023-12-04"));
r |=test(14,"2023-12-03",2,new Date("2023-12-05"));
r |=test(15,"2021-02-01",2,new Date("2021-02-03"));
r |=test(16,"2021-02-01",3,new Date("2021-02-04"));
r |=test(17,"2021-02-01",4,new Date("2021-02-05"));
r |=test(18,"2021-02-01",5,new Date("2021-02-08"));
r |=test(19,"2021-02-01",365,new Date("2022-06-27"));
r |=test(20,"2021-02-01",100,new Date("2021-06-21"));
r |=test(21,"2021-02-01",20000,new Date("2097-09-30"));
r |=test(24,"2023-12-01",-1,new Date("2023-11-30"));
r |=test(25,"2023-12-01",-2,new Date("2023-11-29"));
r |=test(26,"2023-12-01",-3,new Date("2023-11-28"));
r |=test(27,"2023-12-01",-4,new Date("2023-11-27"));
r |=test(28,"2023-12-01",-365,new Date("2022-07-08"));
r |=test(29,"2023-12-01",-100,new Date("2023-07-14"));
r |=test(30,"2023-12-01",-999,new Date("2020-02-03"));
r |=test(31,"2023-12-02",-1,new Date("2023-12-01"));
r |=test(32,"2023-12-02",-2,new Date("2023-11-30"));
r |=test(33,"2023-12-02",-3,new Date("2023-11-29"));
r |=test(34,"2023-12-02",-4,new Date("2023-11-28"));
r |=test(35,"2023-12-02",-365,new Date("2022-07-11"));
r |=test(36,"2023-12-02",-100,new Date("2023-07-17"));
r |=test(37,"2023-12-02",-999,new Date("2020-02-04"));
r |=test(38,"2023-12-03",-1,new Date("2023-12-01"));
r |=test(39,"2023-12-03",-2,new Date("2023-11-30"));
r |=test(40,"2023-12-03",-3,new Date("2023-11-29"));
r |=test(41,"2023-12-03",-4,new Date("2023-11-28"));
r |=test(42,"2023-12-04",-1,new Date("2023-12-01"));
r |=test(43,"2023-12-04",-2,new Date("2023-11-30"));
r |=test(44,"2023-12-04",-3,new Date("2023-11-29"));
r |=test(45,"2023-12-04",-4,new Date("2023-11-28"));
r |=test(46,"2023-12-04",-5,new Date("2023-11-27"));
r |=test(47,"2023-12-04",-6,new Date("2023-11-24"));
r |=test(48,"2023-12-04",-7,new Date("2023-11-23"));
r |=test(49,"2023-12-04",-8,new Date("2023-11-22"));

if (r==0) console.log("✅ (Sat-Sun) Weekend Passed.");

//========================================
// Test with Fri-Sat as weekend
// use example locale 'ar-SA' for Saudi Arabia
//========================================
var r=0; // test tracker
var locale="ar-SA";
r |=test(1,"2023-11-27",1,new Date("2023-11-28"),locale);
r |=test(2,"2023-11-27",0,new Date("2023-11-27"),locale);
r |=test(3,"2023-12-02",0,new Date("2023-12-02"),locale);
r |=test(4,"2023-12-01",0,new Date("2023-12-01"),locale);
r |=test(5,"2023-11-27",2,new Date("2023-11-29"),locale);
r |=test(6,"2023-11-27",3,new Date("2023-11-30"),locale);
r |=test(7,"2023-11-27",4,new Date("2023-12-03"),locale);
r |=test(8,"2023-11-27",5,new Date("2023-12-04"),locale);
r |=test(9,"2023-11-27",6,new Date("2023-12-05"),locale);
r |=test(10,"2023-11-27",7,new Date("2023-12-06"),locale);
r |=test(11,"2023-11-27",8,new Date("2023-12-07"),locale);
r |=test(12,"2023-11-27",9,new Date("2023-12-10"),locale);
r |=test(13,"2023-12-02",1,new Date("2023-12-03"),locale);
r |=test(14,"2023-12-02",2,new Date("2023-12-04"),locale);
r |=test(15,"2023-12-02",3,new Date("2023-12-05"),locale);
r |=test(16,"2023-12-03",1,new Date("2023-12-04"),locale);
r |=test(17,"2023-12-03",2,new Date("2023-12-05"),locale);
r |=test(18,"2021-02-01",2,new Date("2021-02-03"),locale);
r |=test(19,"2021-02-01",3,new Date("2021-02-04"),locale);
r |=test(20,"2021-02-01",4,new Date("2021-02-07"),locale);
r |=test(21,"2021-02-01",5,new Date("2021-02-08"),locale);
r |=test(22,"2021-02-01",365,new Date("2022-06-27"),locale);
r |=test(23,"2021-02-01",100,new Date("2021-06-21"),locale);
r |=test(24,"2021-02-01",20000,new Date("2097-09-30"),locale);
r |=test(25,"2023-12-01",-1,new Date("2023-11-30"),locale);
r |=test(26,"2023-12-01",-2,new Date("2023-11-29"),locale);
r |=test(27,"2023-12-01",-3,new Date("2023-11-28"),locale);
r |=test(28,"2023-12-01",-4,new Date("2023-11-27"),locale);
r |=test(29,"2023-12-01",-365,new Date("2022-07-10"),locale);
r |=test(30,"2023-12-01",-100,new Date("2023-07-16"),locale);
r |=test(31,"2023-12-01",-999,new Date("2020-02-03"),locale);
r |=test(32,"2023-12-02",-1,new Date("2023-11-30"),locale);
r |=test(33,"2023-12-02",-2,new Date("2023-11-29"),locale);
r |=test(34,"2023-12-02",-3,new Date("2023-11-28"),locale);
r |=test(35,"2023-12-02",-4,new Date("2023-11-27"),locale);
r |=test(36,"2023-12-02",-365,new Date("2022-07-10"),locale);
r |=test(37,"2023-12-02",-100,new Date("2023-07-16"),locale);
r |=test(38,"2023-12-02",-999,new Date("2020-02-03"),locale);
r |=test(39,"2023-12-03",-1,new Date("2023-11-30"),locale);
r |=test(40,"2023-12-03",-2,new Date("2023-11-29"),locale);
r |=test(41,"2023-12-03",-3,new Date("2023-11-28"),locale);
r |=test(42,"2023-12-03",-4,new Date("2023-11-27"),locale);
r |=test(43,"2023-12-04",-1,new Date("2023-12-03"),locale);
r |=test(44,"2023-12-04",-2,new Date("2023-11-30"),locale);
r |=test(45,"2023-12-04",-3,new Date("2023-11-29"),locale);
r |=test(46,"2023-12-04",-4,new Date("2023-11-28"),locale);
r |=test(47,"2023-12-04",-5,new Date("2023-11-27"),locale);
r |=test(48,"2023-12-04",-6,new Date("2023-11-26"),locale);
r |=test(49,"2023-12-04",-7,new Date("2023-11-23"),locale);
r |=test(50,"2023-12-04",-8,new Date("2023-11-22"),locale);
if (r==0) console.log("✅ (Fri-Sat) Weekend Passed.");


//========================================
// Test with Thu-Fri as weekend
// use example locale 'ps-AF' for Afghanistan
//========================================
var r=0; // test tracker
var locale="ps-AF";
r |=test(1,"2023-11-27",1,new Date("2023-11-28"),locale);
r |=test(2,"2023-11-27",0,new Date("2023-11-27"),locale);
r |=test(3,"2023-11-30",0,new Date("2023-11-30"),locale);
r |=test(4,"2023-12-01",0,new Date("2023-12-01"),locale);
r |=test(5,"2023-11-27",2,new Date("2023-11-29"),locale);
r |=test(6,"2023-11-27",3,new Date("2023-12-02"),locale);
r |=test(7,"2023-11-27",4,new Date("2023-12-03"),locale);
r |=test(8,"2023-11-27",5,new Date("2023-12-04"),locale);
r |=test(9,"2023-11-27",6,new Date("2023-12-05"),locale);
r |=test(10,"2023-11-27",7,new Date("2023-12-06"),locale);
r |=test(11,"2023-11-27",8,new Date("2023-12-09"),locale);
r |=test(12,"2023-11-27",9,new Date("2023-12-10"),locale);
r |=test(13,"2023-12-02",1,new Date("2023-12-03"),locale);
r |=test(14,"2023-12-02",2,new Date("2023-12-04"),locale);
r |=test(15,"2023-12-02",3,new Date("2023-12-05"),locale);
r |=test(16,"2023-12-03",1,new Date("2023-12-04"),locale);
r |=test(17,"2023-12-03",2,new Date("2023-12-05"),locale);
r |=test(18,"2021-02-01",2,new Date("2021-02-03"),locale);
r |=test(19,"2021-02-01",3,new Date("2021-02-06"),locale);
r |=test(20,"2021-02-01",4,new Date("2021-02-07"),locale);
r |=test(21,"2021-02-01",5,new Date("2021-02-08"),locale);
r |=test(22,"2021-02-01",365,new Date("2022-06-27"),locale);
r |=test(23,"2021-02-01",100,new Date("2021-06-21"),locale);
r |=test(24,"2021-02-01",20000,new Date("2097-09-30"),locale);
r |=test(25,"2021-02-01",-1,new Date("2021-01-31"),locale);
r |=test(26,"2021-02-01",-2,new Date("2021-01-30"),locale);
r |=test(27,"2021-02-01",-3,new Date("2021-01-27"),locale);
r |=test(28,"2021-02-01",-4,new Date("2021-01-26"),locale);
r |=test(29,"2021-02-01",-365,new Date("2019-09-09"),locale);
r |=test(30,"2021-02-01",-100,new Date("2020-09-14"),locale);
r |=test(31,"2021-02-01",-999,new Date("2017-04-04"),locale);
if (r==0) console.log("✅ (Thu-Fri) Weekend Passed.");

//========================================
// Test with Fri as weekend
// use example locale 'fa-IR' for Iran
//========================================
var locale="fa-IR";
var r=0;
r |=test(1,"2023-11-27",1,new Date("2023-11-28"),locale);
r |=test(2,"2023-11-27",2,new Date("2023-11-29"),locale);
r |=test(3,"2023-11-27",3,new Date("2023-11-30"),locale);
r |=test(4,"2023-11-27",4,new Date("2023-12-02"),locale);
r |=test(5,"2023-11-27",5,new Date("2023-12-03"),locale);
r |=test(6,"2023-11-27",6,new Date("2023-12-04"),locale);
r |=test(7,"2023-11-27",7,new Date("2023-12-05"),locale);
r |=test(8,"2023-11-27",8,new Date("2023-12-06"),locale);
r |=test(9,"2023-11-27",9,new Date("2023-12-07"),locale);
r |=test(10,"2023-12-02",1,new Date("2023-12-03"),locale);
r |=test(11,"2023-12-02",2,new Date("2023-12-04"),locale);
r |=test(12,"2023-12-02",3,new Date("2023-12-05"),locale);
r |=test(13,"2023-12-03",1,new Date("2023-12-04"),locale);
r |=test(14,"2023-12-03",2,new Date("2023-12-05"),locale);
r |=test(15,"2021-02-01",2,new Date("2021-02-03"),locale);
r |=test(16,"2021-02-01",3,new Date("2021-02-04"),locale);
r |=test(17,"2021-02-01",4,new Date("2021-02-06"),locale);
r |=test(18,"2021-02-01",5,new Date("2021-02-07"),locale);
r |=test(19,"2021-02-01",365,new Date("2022-04-03"),locale);
r |=test(20,"2021-02-01",100,new Date("2021-05-29"),locale);
r |=test(21,"2021-02-01",20000,new Date("2084-12-20"),locale);
r |=test(22,"2021-02-01",-1,new Date("2021-01-31"),locale);
r |=test(23,"2021-02-01",-2,new Date("2021-01-30"),locale);
r |=test(24,"2021-02-01",-3,new Date("2021-01-28"),locale);
r |=test(25,"2021-02-01",-4,new Date("2021-01-27"),locale);
r |=test(26,"2021-02-01",-365,new Date("2019-12-03"),locale);
r |=test(27,"2021-02-01",-100,new Date("2020-10-07"),locale);
r |=test(28,"2021-02-01",-999,new Date("2017-11-23"),locale);

if (r==0) console.log("✅ (Friday only)   Weekend Passed.");

//========================================
// Test with Sunday as weekend
// use example locale 'en-IN' for India
//========================================
var locale="en-IN";
var r=0;
r |=test(1,"2023-11-27",1,new Date("2023-11-28"),locale);
r |=test(2,"2023-11-27",2,new Date("2023-11-29"),locale);
r |=test(3,"2023-11-27",3,new Date("2023-11-30"),locale);
r |=test(4,"2023-11-27",4,new Date("2023-12-01"),locale);
r |=test(5,"2023-11-27",5,new Date("2023-12-02"),locale);
r |=test(6,"2023-11-27",6,new Date("2023-12-04"),locale);
r |=test(7,"2023-11-27",7,new Date("2023-12-05"),locale);
r |=test(8,"2023-11-27",8,new Date("2023-12-06"),locale);
r |=test(9,"2023-11-27",9,new Date("2023-12-07"),locale);
r |=test(10,"2023-12-02",1,new Date("2023-12-04"),locale);
r |=test(11,"2023-12-02",2,new Date("2023-12-05"),locale);
r |=test(12,"2023-12-02",3,new Date("2023-12-06"),locale);
r |=test(13,"2023-12-03",1,new Date("2023-12-04"),locale);
r |=test(14,"2023-12-03",2,new Date("2023-12-05"),locale);
r |=test(15,"2021-02-01",2,new Date("2021-02-03"),locale);
r |=test(16,"2021-02-01",3,new Date("2021-02-04"),locale);
r |=test(17,"2021-02-01",4,new Date("2021-02-05"),locale);
r |=test(18,"2021-02-01",5,new Date("2021-02-06"),locale);
r |=test(19,"2021-02-01",365,new Date("2022-04-02"),locale);
r |=test(20,"2021-02-01",100,new Date("2021-05-28"),locale);
r |=test(21,"2021-02-01",20000,new Date("2084-12-20"),locale);
r |=test(22,"2021-02-01",-1,new Date("2021-01-30"),locale);
r |=test(23,"2021-02-01",-2,new Date("2021-01-29"),locale);
r |=test(24,"2021-02-01",-3,new Date("2021-01-28"),locale);
r |=test(25,"2021-02-01",-4,new Date("2021-01-27"),locale);
r |=test(26,"2021-02-01",-365,new Date("2019-12-03"),locale);
r |=test(27,"2021-02-01",-100,new Date("2020-10-07"),locale);
r |=test(28,"2021-02-01",-999,new Date("2017-11-23"),locale);

if (r==0) console.log("✅ (Sunday only)   Weekend Passed.");

//========================================
// Test with Sat as weekend
// use example array day 6 [6]
//========================================
var locale=[6];
var r=0;
r |=test(1,"2023-11-27",1,new Date("2023-11-28"),locale);
r |=test(2,"2023-11-27",2,new Date("2023-11-29"),locale);
r |=test(3,"2023-11-27",3,new Date("2023-11-30"),locale);
r |=test(4,"2023-11-27",4,new Date("2023-12-01"),locale);
r |=test(5,"2023-11-27",5,new Date("2023-12-03"),locale);
r |=test(6,"2023-11-27",6,new Date("2023-12-04"),locale);
r |=test(7,"2023-11-27",7,new Date("2023-12-05"),locale);
r |=test(8,"2023-11-27",8,new Date("2023-12-06"),locale);
r |=test(9,"2023-11-27",9,new Date("2023-12-07"),locale);
r |=test(10,"2023-12-02",1,new Date("2023-12-03"),locale);
r |=test(11,"2023-12-02",2,new Date("2023-12-04"),locale);
r |=test(12,"2023-12-02",3,new Date("2023-12-05"),locale);
r |=test(13,"2023-12-03",1,new Date("2023-12-04"),locale);
r |=test(14,"2023-12-03",2,new Date("2023-12-05"),locale);
r |=test(15,"2021-02-01",2,new Date("2021-02-03"),locale);
r |=test(16,"2021-02-01",3,new Date("2021-02-04"),locale);
r |=test(17,"2021-02-01",4,new Date("2021-02-05"),locale);
r |=test(18,"2021-02-01",5,new Date("2021-02-07"),locale);
r |=test(19,"2021-02-01",365,new Date("2022-04-03"),locale);
r |=test(20,"2021-02-01",100,new Date("2021-05-28"),locale);
r |=test(21,"2021-02-01",20000,new Date("2084-12-20"),locale);
r |=test(22,"2021-02-01",-1,new Date("2021-01-31"),locale);
r |=test(23,"2021-02-01",-2,new Date("2021-01-29"),locale);
r |=test(24,"2021-02-01",-3,new Date("2021-01-28"),locale);
r |=test(25,"2021-02-01",-4,new Date("2021-01-27"),locale);
r |=test(26,"2021-02-01",-365,new Date("2019-12-03"),locale);
r |=test(27,"2021-02-01",-100,new Date("2020-10-07"),locale);
r |=test(28,"2021-02-01",-999,new Date("2017-11-23"),locale);

if (r==0) console.log("✅ (Saturday only) Weekend Passed.");

//=====================================
// Tester Function
//=====================================
function test(test,startDate,wDays,should,locale) {
let result = addWorkDays(startDate,wDays,locale);
if (""+result !== ""+should) {
    console.log(`${test}. Output   : ${result}\n    Should be: ${should}`);return 1;
    }
}
Pyorrhea answered 3/12, 2023 at 11:52 Comment(2)
I like this solution a lot, but linters and TypeScript will complain about Date.prototype.getUTCDay() not accepting parameters, even though this works in most browsers. Here is a corrected version: while (numDays) ![6,0].includes(new Date(newDate.setUTCDate(newDate.getUTCDate()+1)).getUTCDay()) && numDays--;Daysidayspring
@TylerV. Thanks for highlighting the linters and typescript issue and the suggested modifications. I will update as suggested.Pyorrhea

© 2022 - 2024 — McMap. All rights reserved.