2

I have two dates. One is starting date and another is ending date. I want to calculate how many Saturdays, Mondays and Wednesdays falls within the date range? How can I solve it? I saw several tutorial but they are only counting the dates within date range. Thanks in advance. I am using the following code to calculate only business days but I need only how many saturdays, mondays and wednesdays falls within the date range.

<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title>JS Bin</title>
<!--[if IE]>
  <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
  <script>
        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) {
          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
    }
    </script>
<style>
  article, aside, figure, footer, header, hgroup, 
  menu, nav, section { display: block; }
</style>
</head>
<body>
  <script>
    alert(calcBusinessDays(new Date("August 01, 2010 11:13:00"),new Date("August 31, 2010 11:13:00")));
  </script>
</body>
</html>
user3150647
  • 45
  • 2
  • 5

2 Answers2

8

O(1) solution. Loops over days of the week (no more than 7), not the date range.

// days is an array of weekdays: 0 is Sunday, ..., 6 is Saturday
function countCertainDays( days, d0, d1 ) {
  var ndays = 1 + Math.round((d1-d0)/(24*3600*1000));
  var sum = function(a,b) {
    return a + Math.floor( (ndays+(d0.getDay()+6-b) % 7 ) / 7 ); };
  return days.reduce(sum,0);
}

For example, to count Mondays (1), Wednesdays (3) and Saturdays (6) in January of 2014:

countCertainDays([1,3,6],new Date(2014,0,1),new Date(2014,0,1)) // 1
countCertainDays([1,3,6],new Date(2014,0,1),new Date(2014,0,2)) // 1
countCertainDays([1,3,6],new Date(2014,0,1),new Date(2014,0,3)) // 1
countCertainDays([1,3,6],new Date(2014,0,1),new Date(2014,0,4)) // 2
countCertainDays([1,3,6],new Date(2014,0,1),new Date(2014,0,5)) // 2
countCertainDays([1,3,6],new Date(2014,0,1),new Date(2014,0,6)) // 3
countCertainDays([1,3,6],new Date(2014,0,1),new Date(2014,0,7)) // 3
countCertainDays([1,3,6],new Date(2014,0,1),new Date(2014,0,8)) // 4
countCertainDays([1,3,6],new Date(2014,0,1),new Date(2014,0,9)) // 4
countCertainDays([1,3,6],new Date(2014,0,1),new Date(2014,0,10)) // 4
countCertainDays([1,3,6],new Date(2014,0,1),new Date(2014,0,11)) // 5

Note: This assumes d0 and d1 are Date objects whose time of day are about the same. If you create Date objects only specifying year, month, and day, then there is no problem.

Matt
  • 20,108
  • 1
  • 57
  • 70
4

My approach:

First, acquire a list of dates from a range between two dates:

function getDates(dateStart, dateEnd) {
  var currentDate = dateStart,
      dates = [];
  while(currentDate <= dateEnd) {

    // append date to array
    dates.push(currentDate);

    // add one day
    // automatically rolling over to next month
    var d = new Date(currentDate.valueOf());
    d.setDate(d.getDate() + 1);
    currentDate = d;

  }
  return dates;
}

Then cycle through those dates, filtering for a relevant work day index:

function filterWeekDays(dates, includeDays) {
  var weekdays = [];

  // cycle dates
  dates.forEach(function(day){

    // cycle days to be included (so==0, mo==1, etc.)
    includeDays.forEach(function(include) {
      if(day.getDay() == include) {
        weekdays.push(day);
      }
    });
  });
  return weekdays;
}

Filtering options:

With Sunday beeing 0 and Monday being 1, a list of Sun, Mon, Wed would be: [0, 1, 3]

JS Bin: http://jsbin.com/furupoqu/5/edit

Jakob Hohlfeld
  • 1,503
  • 1
  • 17
  • 31
  • Thank you very much. I have checked the codes. Its working fine. I think there is only one issue. Its not counting the last date. Such as if the end date fall within workdays then the result returning 1 day less than actual result. In january 01, 2014 to january 31, 2014 if the workdays are saturday, monday and wednesday then the result returning 13 workdays whereas if I put January 29, 2014 as my end date which is also wednesday its returning 12 workingdays which should be 13. – user3150647 Feb 25 '14 at 04:53
  • I changed the answer. Take a look at the while statement. It should now include the endDate. – Jakob Hohlfeld Feb 25 '14 at 08:47
  • This is very useful. Is there any formula that i can give an array of dates too which will be exclude or will not count between two dates? – Poonam Jul 20 '16 at 12:27