18

Hi i am using jquery-ui datepicker to select date and date.js to find difference between 2 dates.

Right now the problem is I want to exclude weekend days from calculation (saturday and sunday). How should i do that?

For example the user select start date (13/8/2010) and end date (16/8/2010). Since 14/8/2010 and 15/8/2010 is in week days, instead of 4 days total, i want it to be only 2 days.

This is the code im using right now:

<script type="text/javascript">

    $("#startdate, #enddate").change(function() {       

    var d1 = $("#startdate").val();
    var d2 = $("#enddate").val();

            var minutes = 1000*60;
            var hours = minutes*60;
            var day = hours*24;

            var startdate1 = getDateFromFormat(d1, "d-m-y");
            var enddate1 = getDateFromFormat(d2, "d-m-y");

            var days = 1 + Math.round((enddate1 - startdate1)/day);             

    if(days>0)
    { $("#noofdays").val(days);}
    else
    { $("#noofdays").val(0);}


    });

    </script>
cyberfly
  • 5,568
  • 8
  • 50
  • 67

13 Answers13

23

Maybe someone else can help you converting this function into JQuery's framework...

I found this function here.

function calcBusinessDays(dDate1, dDate2) { // input given as Date objects
  var iWeeks, iDateDiff, iAdjust = 0;
  if (dDate2 < dDate1) return -1; // error code if dates transposed
  var iWeekday1 = dDate1.getDay(); // day of week
  var iWeekday2 = dDate2.getDay();
  iWeekday1 = (iWeekday1 == 0) ? 7 : iWeekday1; // change Sunday from 0 to 7
  iWeekday2 = (iWeekday2 == 0) ? 7 : iWeekday2;
  if ((iWeekday1 > 5) && (iWeekday2 > 5)) iAdjust = 1; // adjustment if both days on weekend
  iWeekday1 = (iWeekday1 > 5) ? 5 : iWeekday1; // only count weekdays
  iWeekday2 = (iWeekday2 > 5) ? 5 : iWeekday2;

  // calculate differnece in weeks (1000mS * 60sec * 60min * 24hrs * 7 days = 604800000)
  iWeeks = Math.floor((dDate2.getTime() - dDate1.getTime()) / 604800000)

  if (iWeekday1 < iWeekday2) { //Equal to makes it reduce 5 days
    iDateDiff = (iWeeks * 5) + (iWeekday2 - iWeekday1)
  } else {
    iDateDiff = ((iWeeks + 1) * 5) - (iWeekday1 - iWeekday2)
  }

  iDateDiff -= iAdjust // take into account both days on weekend

  return (iDateDiff + 1); // add 1 because dates are inclusive
}

var date1 = new Date("August 11, 2010 11:13:00");
var date2 = new Date("August 16, 2010 11:13:00");
alert(calcBusinessDays(date1, date2));

## EDITED ##

If you want to use it with your that format just:

Your code will look like:

function calcBusinessDays(dDate1, dDate2) { // input given as Date objects
  var iWeeks, iDateDiff, iAdjust = 0;
  if (dDate2 < dDate1) return -1; // error code if dates transposed
  var iWeekday1 = dDate1.getDay(); // day of week
  var iWeekday2 = dDate2.getDay();
  iWeekday1 = (iWeekday1 == 0) ? 7 : iWeekday1; // change Sunday from 0 to 7
  iWeekday2 = (iWeekday2 == 0) ? 7 : iWeekday2;
  if ((iWeekday1 > 5) && (iWeekday2 > 5)) iAdjust = 1; // adjustment if both days on weekend
  iWeekday1 = (iWeekday1 > 5) ? 5 : iWeekday1; // only count weekdays
  iWeekday2 = (iWeekday2 > 5) ? 5 : iWeekday2;

  // calculate differnece in weeks (1000mS * 60sec * 60min * 24hrs * 7 days = 604800000)
  iWeeks = Math.floor((dDate2.getTime() - dDate1.getTime()) / 604800000)

  if (iWeekday1 < iWeekday2) { //Equal to makes it reduce 5 days
    iDateDiff = (iWeeks * 5) + (iWeekday2 - iWeekday1)
  } else {
    iDateDiff = ((iWeeks + 1) * 5) - (iWeekday1 - iWeekday2)
  }

  iDateDiff -= iAdjust // take into account both days on weekend

  return (iDateDiff + 1); // add 1 because dates are inclusive
}


$("#startdate, #enddate").change(function() {

  var d1 = $("#startdate").val();
  var d2 = $("#enddate").val();

  var minutes = 1000 * 60;
  var hours = minutes * 60;
  var day = hours * 24;

  var startdate1 = new Date(d1);
  var enddate1 = new Date(d2);


  var newstartdate = new Date();
  newstartdate.setFullYear(startdate1.getYear(), startdate1.getMonth(), startdate1.getDay());
  var newenddate = new Date();
  newenddate.setFullYear(enddate1.getYear(), enddate1.getMonth(), enddate1.getDay());
  var days = calcBusinessDays(newstartdate, newenddate);
  if (days > 0) {
    $("#noofdays").val(days);
  } else {
    $("#noofdays").val(0);
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<label>Start Date
 <input type="date" id="startdate" value="2019-03-03"/>
</label>

<label>End Date
 <input type="date" id="enddate" value="2019-03-06"/>
</label>

<label>N. of days
 <output id="noofdays"/>
</label>
squaleLis
  • 6,116
  • 2
  • 22
  • 30
Garis M Suero
  • 7,974
  • 7
  • 45
  • 68
  • thanks for the quick reply. will give this code a try and hope can solve my problem :) – cyberfly Aug 12 '10 at 02:38
  • To use it in your code use stardate1 and enddate1 as the parameters for the calcBusinessDays(date, date) function... – Garis M Suero Aug 12 '10 at 02:42
  • the script doesnt accept this date format (11-08-2010). trying to figure out now. – cyberfly Aug 12 '10 at 03:05
  • By the way, the function getDateFromFormat return a javascript Date object right?... because the function i've just posted accept Date objects as parameters – Garis M Suero Aug 12 '10 at 03:16
  • 1
    thanks i get it work although the code is bit different. anyway thank very much for your help. I have been stucked by this problem for 2 days until i found stackoverflow and your great help. – cyberfly Aug 12 '10 at 03:18
  • 2
    +1 for posting a reference to the original code! I actually didn't see that when I looked at the post originally. The +1 is also because the code IS faster than my solution, but not by much :) – sberry Aug 12 '10 at 04:05
  • `setFullYear` accepts only a year as parameter... better pass those params to the `new Date()` instead.. – Gabriele Petrioli Jul 07 '12 at 18:09
  • 2
    @GarisMSuero calcBusinessDays it does not work for any two dates, try it with '20140328' and '20140404'; the result is 0, which is wrong; this happens because of UTC offset; please check in this post, Michael Liu's answer: http://stackoverflow.com/questions/542938/how-do-i-get-the-number-of-days-between-two-dates-in-javascript – Flavia Obreja Jun 10 '14 at 09:37
  • @FlaviaObreja I've just tried and it returned 6 days. Please notice that the right format is 2014-03-28 and 2014-04-04 http://jsbin.com/ufoze4/318/ – Garis M Suero Jun 10 '14 at 14:24
  • @GarisMSuero i think my example worked for you because you have other date start for the daylight saving time. Please check the following jsfiddle where i made two examples, one using the begining of daylight saving date in US and the other one is for european union, to cover both cases: http://jsfiddle.net/ma34r/ – Flavia Obreja Jun 10 '14 at 22:21
  • 2
    This script doesn't work properly. It shows 1 day when starting in a sunday and ending the Friday ahead. [Reproduction of the bug here](http://jsfiddle.net/e6gmkLwg/) – Alvaro Feb 19 '15 at 12:08
  • 3
    It is giving wrong result.If you are selecting start date " 06-11-2015" and end date " 06-18-2015"..it is giving the result as 1. It should be 5 – JOJO Jun 11 '15 at 11:54
  • 1
    I modified your solution so it would work if the start date was a saturday or a sunday. – Tim Gerhard Feb 14 '19 at 10:07
17

To do this, you should NOT search all days between these dates !

It's not complicated, look some evident assumptions:

  1. All full-week has 7-days.

  2. Which 2 are weekend-days.

  3. And which 5 are business-day.

Evident conclusions:

  1. Look all days is loss of time.

  2. Check what day is weekend to all week is loss of time.


Without tedious explanation.. let me show the code:

function getBusinessDateCount (startDate, endDate) {
    var elapsed, daysBeforeFirstSaturday, daysAfterLastSunday;
    var ifThen = function (a, b, c) {
        return a == b ? c : a;
    };

    elapsed = endDate - startDate;
    elapsed /= 86400000;

    daysBeforeFirstSunday = (7 - startDate.getDay()) % 7;
    daysAfterLastSunday = endDate.getDay();

    elapsed -= (daysBeforeFirstSunday + daysAfterLastSunday);
    elapsed = (elapsed / 7) * 5;
    elapsed += ifThen(daysBeforeFirstSunday - 1, -1, 0) + ifThen(daysAfterLastSunday, 6, 5);

    return Math.ceil(elapsed);
}

function calc() {
  let start = document.querySelector('#startDate').value,
      end = document.querySelector('#endDate').value,
      result = getBusinessDateCount(new Date(start), new Date(end));
  document.querySelector('#result').value = result;
}
Start date: <input type="date" id="startDate" value="2020-01-04"><br>
End date: <input type="date" id="endDate" value="2020-01-06"><br>
<input type="button" onclick="calc()" value="Get business days"><br>
Business days: <input id="result" readonly>

You can test it yourself with any dates.

I just want to notice that this code ONLY consumed 0.43 sec between dates from 2000 to 2015... It is much more fast than some other codes.

Hope it helps...

Nice coding !!

RobG
  • 142,382
  • 31
  • 172
  • 209
  • It doesn't count properly when starting on a weekend [Reproduction of the bug](http://jsfiddle.net/ho02j7yt/). Its counting 3 days when it should be 5. – Alvaro Dec 15 '15 at 11:16
  • @Alvaro. Many thanks for the reply.. I've updated the function.. Check if it works for you now –  Dec 15 '15 at 13:47
  • 1
    Thanks a lot for it, it seems to be working properly now! – Alvaro Dec 16 '15 at 10:15
  • Thanks for this great bit of code. There is, however, an error. You've defined `daysBeforeFirstSaturday` on the first line, but you are referencing `daysBeforeFirstSunday` throughout the function. I assume this is a typo. – fix Jun 08 '22 at 14:43
9

This is how I would do it

function getDays(d1, d2) {
    var one_day=1000*60*60*24;
    var d1_days = parseInt(d1.getTime()/one_day) - 1;
    var d2_days = parseInt(d2.getTime()/one_day);
    var days = (d2_days - d1_days);
    var weeks = (d2_days - d1_days) / 7;
    var day1 = d1.getDay();
    var day2 = d2.getDay();
    if (day1 == 0) {
        days--;
    } else if (day1 == 6) {
        days-=2;
    }
    if (day2 == 0) {
       days-=2;
    } else if (day2 == 6) {
       days--;
    }
    days -= parseInt(weeks) * 2;
    alert(days);
}

getDays(new Date("June 8, 2004"),new Date("February 6, 2010"));

EDIT
To clarify my comment to @keenebec...
That solution will work for small date differences quite nicely and is easy to understand. But take something as "short" as a 6 year span and you can see a remarkable difference in speed.

http://jsfiddle.net/aSvxv/

I included all 3 answers and the original answer is indeed the fastest, but not by much and the trade off for a few microseconds of execution is somewhat trivial to me in favor of readability.

sberry
  • 128,281
  • 18
  • 138
  • 165
  • This should be the accepted answer. The one by Garis has bugs starting and finishing on weekends ([reproduction of Garis bug](http://jsfiddle.net/e6gmkLwg/)) – Alvaro Feb 19 '15 at 12:35
  • This is an old post, but was wondering if there's any way to modify this to take time also into consideration and provide the difference in days as a fraction - Ex: Difference between 2 timestamps is 2.35 days after excluding weekends – Plasty Grove Mar 02 '15 at 09:07
  • Failing when starting in Thusday and finishing in Monday. [Reproduction of the bug](http://jsfiddle.net/4ajs66qa/). There are 3 working days and its reporting 5. – Alvaro Dec 15 '15 at 10:36
  • To fix the bug where if day2 is less than day1: `if (day2 < day1) weeks++;` – javon27 Jun 02 '16 at 20:24
4

Date.prototype.addDays = function(days) {
    var date = new Date(this.valueOf())
    date.setDate(date.getDate() + days);
    return date;
}

function getBusinessDatesCount(startDate, endDate) {
    var count = 0;
    var curDate = startDate;
    while (curDate <= endDate) {
        var dayOfWeek = curDate.getDay();
        var isWeekend = (dayOfWeek == 6) || (dayOfWeek == 0); 
        if(!isWeekend)
           count++;
        curDate = curDate.addDays(1);
    }
    return count;
}



//Usage
var startDate = new Date('7/16/2015');
var endDate = new Date('7/20/2015');
var numOfDays = getBusinessDatesCount(startDate,endDate);
jQuery('div#result').text(numOfDays);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="result"/>
Vadim Gremyachev
  • 57,952
  • 20
  • 129
  • 193
1

That looks like too much work to me. I'd rather let the computer do the heavy lifting- //

Date.bizdays= function(d1, d2){
    var bd= 0, dd, incr=d1.getDate();
    while(d1<d2){
        d1.setDate(++incr);
        dd= d1.getDay();
        if(dd%6)++bd;
    }
    return bd;
}

//test

var day1= new Date(2010, 7, 11), day2= new Date(2010, 7, 31);

alert(Date.bizdays(day1, day2))
sberry
  • 128,281
  • 18
  • 138
  • 165
kennebec
  • 102,654
  • 32
  • 106
  • 127
  • this is definitely a very feasible solution. However, it does mean a "fairly" high number of iterations which may or may not be significant overhead on the client's machine, but fine answer none-the-less. – sberry Aug 12 '10 at 03:30
  • How about losing the biggest chunk of the work by getting floor((d2-d1)/7)? That gives you the number of weeks, which will all contain 5 business days. Then use your roll-forward to finish it off. – Phil H Apr 18 '11 at 06:35
1

To understand way.,


  1. Actual days = 14
  2. weeks for Actual days = 14/7=2
  3. Weekends per week=2
  4. Total weekends=2*weeks for days

So apply this ,

 $('#EndDate').on('change', function () {
            var start = $('#StartDate').datepicker('getDate');
            var end = $('#EndDate').datepicker('getDate');
            if (start < end) {
                var days = (end - start) / 1000 / 60 / 60 / 24;

                var Weeks=Math.round(days)/7;

                var totalWeekends=Math.round(Weeks)*2;

                var puredays=Math.round(days)-totalWeekends;

                $('#days').text(Math.round(puredays) + "Working Days");


            }
            else {
alert("");
}

Thank you !

Thisara Subath
  • 635
  • 6
  • 16
1

Important: Most answers here don't actually work if the start date (or sometimes the end date) is a saturday or sunday. I took the accepted response and modified it so that this issue is resolved now:

    var dateDiff;
    if (dateTo < dateFrom) return -1; // error code if dates transposed
    var dateFromDayOrig = dateFrom.getDay(); // day of week
    var dateToDayOrig = dateTo.getDay();
    var dateFromDay = (dateFromDayOrig == 0) ? 7 : dateFromDayOrig; // change Sunday from 0 to 7
    var dateToDay = (dateToDayOrig == 0) ? 7 : dateToDayOrig;
    dateFromDay = (dateFromDay > 5) ? 5 : dateFromDay; // only count weekdays
    dateToDay = (dateToDay > 5) ? 5 : dateToDay;

    // calculate differnece in weeks (1000mS * 60sec * 60min * 24hrs * 7 days = 604800000)
    var weekDifference = Math.floor((dateTo.getTime() - dateFrom.getTime()) / 604800000);

    if (dateFromDay <= dateToDay) {
        dateDiff = (weekDifference * 5) + (dateToDay - dateFromDay);
    } else {
        dateDiff = ((weekDifference + 1) * 5) - (dateFromDay - dateToDay);
    }

    // fix: remove one day if it's saturday or sunday
    if (dateFromDayOrig >= 6 || dateFromDayOrig == 0) {
    dateDiff--;
    }

    return (dateDiff + 1); // add 1 because dates are inclusive
Tim Gerhard
  • 3,477
  • 2
  • 19
  • 40
  • i've been using this code for a while and it's been mostly very reliable, but i've now realised there's a flaw where it gives a weekdifference of 0 if theres 7 days difference between the dates ` dateTo: Tue May 11 2021 23:59:59 GMT+0100 (British Summer Time)` ` dateFrom: Tue May 04 2021 00:00:00 GMT+0100 (British Summer Time)` ` weekDifference: 0days` – az1d May 11 '21 at 08:05
  • eg: startDate: 1620319036957 endDate: 1620860400000 weekdifference returns: 0 – az1d May 13 '21 at 12:56
1

There seems to be few issues with the response that has been marked as solution.

  • The statement setFullYear() is returning incorrect value if I choose start date as 06/11/2015. So instead, the startDate1 and endDate1 can be directly passed to the function.

  • If the start date is Saturday or Sunday, still the code is counting it(iWeekday1) as 5 days

  • If the end date is Saturday or Sunday, still the code is counting it(iWeekday2) as 5 days. But these 5 days already get counted in the iweeks calculation.
    So instead of
    iWeekday1 = (iWeekday1 > 5) ? 5 : iWeekday1; // only count weekdays
    iWeekday2 = (iWeekday2 > 5) ? 5 : iWeekday2;

    it should be
    iWeekday1 = (iWeekday1 > 5) ? 0 : iWeekday1; // only count weekdays
    iWeekday2 = (iWeekday2 > 5) ? 0 : iWeekday2;

  • The last IF condition should be executed when start and end date day is same like both are on same day, the date could be different
    if (iWeekday1 <= iWeekday2)

  • The condition that adjusts if both days are weekends can be removed
    iDateDiff -= iAdjust

  • Lastly, the +1 should be done only if start and end date falls on weekdays. Currently, it is adding in both the cases.
    return (iDateDiff + 1);//Add condition to apply only if both days are weekdays

--can't comment on that answer as I do not have that reputation :)

Andy
  • 31
  • 4
0

What I did

function calcbusinessdays()
{
    for(var c=0,e=0,d=new Date($("#startdate").val()),a=(new Date($("#enddate").val())-d)/864E5;0<=a;a--)
    {
        var b=new Date(d);
        b.setDate(b.getDate()+a);
        1==Math.ceil(b.getDay()%6/6)?c++:e++
    }
    $("#noofdays").html(c)
};

c is weekdays, e is weekends

0

I get it work with this code. Note that the function is from date.js and businessday js (thanks to Garis Suero). Start Date 11-08-2010 End Date 16-08-2010 will result 4 days of leave.

<script type="text/javascript">

    $("#startdate, #enddate").change(function() {       

    var d1 = $("#startdate").val();
    var d2 = $("#enddate").val();

            var minutes = 1000*60;
            var hours = minutes*60;
            var day = hours*24;

            var startdate1 = getDateFromFormat(d1, "d-m-y");
            var enddate1 = getDateFromFormat(d2, "d-m-y");

            var days = calcBusinessDays(new Date(startdate1),new Date(enddate1));             

    if(days>0)
    { $("#noofdays").val(days);}
    else
    { $("#noofdays").val(0);}


    });

    </script>
cyberfly
  • 5,568
  • 8
  • 50
  • 67
0
function addDays(date, days) {
    var result = new Date(date);
    result.setDate(result.getDate() + days);
    return result;
}
 var currentDate;
                            selectFlixbleDates = [];
                            var monToSatDateFilter=[];
                            currentDate=new Date(date);
                            while(currentDate){
                                console.log("currentDate"+currentDate);
                                if(new Date(currentDate).getDay()!=0){
                                    selectFlixbleDates.push(currentDate)
                                }
                                if(selectFlixbleDates.length==$scope.numberOfDatePick)
                                {

                                    break;
                                }
                                currentDate=addDays(currentDate,1);

                            }
                            for (var i = 0; i < selectFlixbleDates.length; i++) {

                                //  console.log(between[i]);
                                monToSatDateFilter.push((selectFlixbleDates[i].getMonth() + 1) + '/' + selectFlixbleDates[i].getDate() + '/' + selectFlixbleDates[i].getFullYear());

                            }
                            var endDate=monToSatDateFilter.slice(-1).pop();
                            var space =monToSatDateFilter.join(', ');
                            var sdfs= document.getElementById("maxPicks").value =space;
                            $scope.$apply(function() {
                                $scope.orderEndDate=monToSatDateFilter.slice(-1).pop()
                                $scope.orderStartDate=monToSatDateFilter[0];
                            });
                            document.getElementById("startDateEndDate").innerHTML =$scope.orderStartDate+ ' TO ' +$scope.orderEndDate
                        }  
sudheer nunna
  • 1,659
  • 15
  • 17
0

I have used Angular framework and Moment.js library to implement the solution. My solution covers all the cases.

this.daysInBetween = this.endMoment.diff(this.startMoment, 'days') + 1;
this.weeksInBetween = this.endMoment.diff(this.startMoment, 'weeks');
this.weekDays = this.daysInBetween - (this.weeksInBetween * 2);

if ( (this.startMoment.day() === 0 && this.endMoment.day() === 6) ||
 (this.startMoment.day() > this.endMoment.day()) ) {
  // IF ONE WEEKEND WAS MISSED
  this.weekDays-=2;
} else if ( this.startMoment.day() <= this.endMoment.day() &&
( this.startMoment.day() === 0 || this.startMoment.day() === 6 ||
  this.endMoment.day() === 0 || this.endMoment.day() === 6) ) {
  // IF EITHER OF DAYS WAS A WEEKEND
  this.weekDays--;
}

Live Demo: Calculate number of weekdays

I am currently working on a blog to write about my approach to this specific problem. I will post the link to the blog on the comment.

Prakash M.
  • 479
  • 8
  • 26
0

Important: Most answers here don't actually work if the start date (or sometimes the end date) is a saturday or sunday. For example: if your start and end date are

  • Saturday to Sunday or vice versa
  • or Saturday to Saturday
  • or Sunday to Sunday

So, here is the modified answer from the accepted answer

function calculateBusinessDays(dDate1, dDate2) {

var iWeeks, iDateDiff, iAdjust = 0;
if (dDate2 < dDate1) {
    return -1;
}

var iWeekday1 = dDate1.getDay();
var iWeekday2 = dDate2.getDay();

iWeekday1 = (iWeekday1 === 0) ? 7 : iWeekday1;
iWeekday2 = (iWeekday2 === 0) ? 7 : iWeekday2;

if (iWeekday1 > 5 && iWeekday2 <= 6) {
    iWeekday1 = 0;
    iAdjust = 1;
}
iWeekday2 = (iWeekday1 === 0 && iWeekday2 === 6) ? 0 : iWeekday2;

if ((iWeekday1 > 5) && (iWeekday2 > 5)) iAdjust = 1;

iWeekday1 = (iWeekday1 > 5) ? 5 : iWeekday1;
iWeekday2 = (iWeekday2 > 5) ? 5 : iWeekday2;
iWeeks = Math.floor((dDate2.getTime() - dDate1.getTime()) / 604800000);

if (iWeeks===0 && iWeekday1===0 && iWeekday2===0 
    && (dDate2.getTime() !== dDate1.getTime()) ) {
    iWeeks = 1;
}

if (iWeekday1 <= iWeekday2) {
    iDateDiff = (iWeeks * 5) + (iWeekday2 - iWeekday1)
} else {
    iDateDiff = ((iWeeks + 1) * 5) - (iWeekday1 - iWeekday2)
}
iDateDiff -= iAdjust
return (iDateDiff + 1);

}