We help IT Professionals succeed at work.

# Number of working days between two dates

on
Medium Priority
1,773 Views
Hi,

Before we go any further, no this is not homework. I have a requirement to create a function or functions, purely in javascript, that can return the number of days between 2 dates excluding weekends. Holidays etc., do not matter. I have found a page that claims to do it:

This seems to work but I get some odd results in testing. Here is what I have so far. Please feel free to let me know where I am going wrong or if you have a better solution, please advise. Please note, I am creating 2 date strings in the form dd/mm/yyyy. These are generated from the 2 input strings sContractSigned and sClosed. Now using the 2 example dates of the 14th and 19th Feb I would expect to get an answer of 4 days as the 14th is a Saturday, it should discount Sunday and only count Monday to Thursday but it gives me 3 as an answer. If I change the 14th to the 15th the answer sholdn't change but it does. It returns 4 instead. Everything is UK formatted.

Any help I would really appreciate.

Thanks,

Lee

``````<html>
<body>

<script type="text/javascript">
Date.prototype.dayDiff = function(d2)
{
var d = Math.abs(this - d2);
return Math.floor(d / (24 * 60 * 60 * 1000));
}

Date.prototype.busDayDiff = function(d2)
{
var d = this.dayDiff(d2);
var t= d%7;

if (this < d2) {w1 = this.getDay(); w2 = d2.getDay();}
else {w2 = this.getDay(); w1 = d2.getDay();}

if (w1 > w2) {t -= 2;}
if (w1 == 0 && w2 == 6) {t--;}
return Math.abs((Math.floor(d / 7) * 5) + t);
}

var sContractSigned = "14/02/2009 00:00:00"
var arrContractSignedDateTime = sContractSigned.split(" ");
var arrContractSignedDate = arrContractSignedDateTime[0].split("/");
var dtContractSigned = new Date(arrContractSignedDate[2], arrContractSignedDate[1], arrContractSignedDate[0]);
var sClosed = "19/02/2009 00:00:00";
var arrClosedDateTime = sClosed.split(" ");
var arrClosedDate = arrClosedDateTime[0].split("/");
var dtClosed = new Date(arrClosedDate[2], arrClosedDate[1], arrClosedDate[0]);
var iNumWorkingDays = dtClosed.busDayDiff(dtContractSigned);

document.write("Contract Signed: " + sContractSigned);
document.write("<br>Closed: " + sClosed);
document.write("<br>Days Diff: " + iNumWorkingDays);
document.write("<br>arrContractSignedDate: " + arrContractSignedDate[2] + " " + arrContractSignedDate[1] + " " + arrContractSignedDate[0]);
document.write("<br>arrClosedDate: " + arrClosedDate[2] + " " + arrClosedDate[1] + " " + arrClosedDate[0]);

</script>

</body>
</html>
``````
Comment
Watch Question

## View Solution Only

Software Engineer
CERTIFIED EXPERT

Commented:
Remember that the Date() object constructor expects the month number to
be from 0..11, not 1..12
Software Engineer
CERTIFIED EXPERT

Commented:

``````var dtContractSigned = new Date( parseInt( arrContractSignedDate[ 2 ] ),
parseInt( arrContractSignedDate[ 1 ] ) - 1, paseeInt( arrContractSignedDate[ 0 ] ) );
``````
Software Engineer
CERTIFIED EXPERT

Commented:
you need to use something like:

``````parseInt( arrContractSignedDate[ 1 ], 10 ) - 1
``````
Software Engineer
CERTIFIED EXPERT

Commented:
For example, try this:
``````var str = '14/02/2009'
var arr = str.split( '/' )
var day = new Date( parseInt( arr[ 2 ] ),
parseInt( arr[ 1 ], 10 ) - 1,
parseInt( arr[ 0 ], 10 ) )

function D2( val ) {
return ( val ) < 10 ? '0' + val : val
}

document.write( D2( day.getDate() ) + '/' +
D2( day.getMonth() + 1 ) + '/' +
day.getFullYear()
)
``````
Software Engineer
CERTIFIED EXPERT

Commented:
whole thing
``````<html>
<title>Q_24130760</title>
<script type="text/javascript">
Date.prototype.dayDiff = function( d2 ) {
var d = Math.abs( this - d2 );
return Math.floor(d / (24 * 60 * 60 * 1000));
}

Date.prototype.busDayDiff = function( d2 ) {
var d = this.dayDiff( d2 );
var t = d % 7;

if ( this < d2 ) {
w1 = this.getDay();
w2 = d2.getDay();
}	else {
w2 = this.getDay();
w1 = d2.getDay();
}

if ( w1 > w2 ) {
t -= 2;
}
if ( w1 == 0 && w2 == 6) {
t--;
}
return Math.abs( ( Math.floor( d / 7 ) * 5 ) + t );
}

//----------------------------------------------------------------------------
// Name: D2()
// Role: Prepend a '0' if the specified value is only 1 digit long
//----------------------------------------------------------------------------
function D2( val ) {
return ( val < 10 ) ? '0' + val : val
}

//----------------------------------------------------------------------------
// Name: Edate()
// Role: Convert European date string to a date object
//----------------------------------------------------------------------------
function Edate( str ) {
var result = new Date()
if ( /(\d{1,2})([-\/])(\d{1,2})\2(\d{4})/.exec( str ) ) {
var mon = RegExp.\$3
var day = RegExp.\$1
var yr  = RegExp.\$4
result = new Date( parseInt( yr ), parseInt( mon, 10 ) - 1, parseInt( day ) )
//    alert( 'Edate( "' + str + '" ) = ' + D2( result.getDate() ) + '/' + D2( result.getMonth() + 1 ) + '/' + result.getFullYear() )
} else {
alert( 'Edate( "' + str + '" ) : unexpected date format' )
}
return result
}
</script>

<body>
<script type="text/javascript">
var sContractSigned = "14/02/2009 00:00:00"
Edate( sContractSigned )
var dtContractSigned = Edate( sContractSigned )

var sClosed = "19/02/2009 00:00:00"
var dtClosed = Edate( sClosed )

var iNumWorkingDays = dtClosed.busDayDiff( dtContractSigned )

document.write("Contract Signed: " + sContractSigned )
document.write("<br>Closed: " + sClosed )
document.write("<br>Business Days: " + iNumWorkingDays )
//document.write("<br>arrContractSignedDate: " + arrContractSignedDate[2] + " " + arrContractSignedDate[1] + " " + arrContractSignedDate[0])
//document.write("<br>arrClosedDate: " + arrClosedDate[2] + " " + arrClosedDate[1] + " " + arrClosedDate[0])
</script>

</body>
</html>
``````
Software Engineer
CERTIFIED EXPERT

Commented:
ooh... I finally went back, and reread the whole thing... (sigh).

The reason you are getting 3 is that the starting and ending days are not counted.  So, the only "work" days are:

16/02/2009
17/02/2009
18/02/2009
Software Engineer
CERTIFIED EXPERT
Commented:
If you would prefer to understand the computation, you could replace the
busDaysDiff() with something like:

If you did, then you could figure out a way to add some data structure
(probably an associative array, indexed by date objects) of "holidays"

Then, the "test" would change from

if ( dow > 0 && dow < 6 ) {

to something like:

if ( dow > 0 && dow < 6 && !holiday[ d ] ) {
``````  //----------------------------------------------------------------------------
// Name: busDayDiff()
// Role: Compute the number of work days between two date objects
//----------------------------------------------------------------------------
Date.prototype.busDayDiff = function( d2 ) {
var result = 0

if ( this < d2 ) {
var start  = this
var fini   = d2
} else {
var start  = d2
var fini   = this
}

for ( var d = start; d < fini; d.setDate( d.getDate() + 1 )  ) {
var dow = d.getDay()
if ( dow > 0 && dow < 6 ) {
result++
//      alert( 'workday: ' + USdate( d ) )
}
}

return result
}
``````

Not the solution you were looking for? Getting a personalized solution is easy.

CERTIFIED EXPERT

Commented:
Hi,

I think we're close here. I have taken your code and restructured it to fit our coding requirements but the functionality is the same. See below. There is a problem though. Using the sContractSignedDate as it is below, I correctly get the number of days as 4. The 13th is a Friday. If I change it to the 14th or 15th Feb, the number of days should not change as these are weekend dates, but it returns 3 which is not correct. It seems that if the sContractSignedDate is a weekend, the number will be one less that what it should. Technically the contract signed date will never be a weekend but this feature relies on the condition not being likely rather than not being possible. I guess I need to add code in to check to see if the contract signed date is a weekend date, and if so, add one to the result. If you could push me in the right direction I would be grateful as my brain is fried with some heavy coding today.

Thanks,

Lee

``````<html>
<body>

<script type="text/javascript">
Date.prototype.busDayDiff = function(pdtEndDate)
{
var iNumDays = 0;

if (this < pdtEndDate)
{
var dtStartDate = this;
var dtEndDate = pdtEndDate;
}
else
{
var dtStartDate = pdtEndDate;
var dtEndDate = this;
}

for (var d = dtStartDate; d < dtEndDate; d.setDate(d.getDate() + 1))
{
var iDOW = d.getDay();

if (iDOW > 0 && iDOW < 6)
{
iNumDays++;
}
}

return iNumDays;
}

var sContractSigned = "13/02/2009 00:00:00"
var sClosed = "19/02/2009 00:00:00";
var arrContractSignedDateTime = sContractSigned.split(" ");
var arrContractSignedDate = arrContractSignedDateTime[0].split("/");
var dtContractSigned = new Date(parseInt(arrContractSignedDate[2]), parseInt(arrContractSignedDate[1]) - 1, parseInt(arrContractSignedDate[0]));
var arrClosedDateTime = sClosed.split(" ");
var arrClosedDate = arrClosedDateTime[0].split("/");
var dtClosed = new Date(parseInt(arrClosedDate[2]), parseInt(arrClosedDate[1]) - 1, parseInt(arrClosedDate[0]));
var iNumWorkingDays = dtContractSigned.busDayDiff(dtClosed);

document.write("Contract Signed: " + sContractSigned);
document.write("<br>Closed: " + sClosed);
document.write("<br>Days Diff: " + iNumWorkingDays);
</script>

</body>
</html>
``````
CERTIFIED EXPERT

Commented:
Hang on, I had a moment of clarity...

Lee

``````Date.prototype.busDayDiff = function(pdtEndDate)
{
var iNumDays = 0;

if (this < pdtEndDate)
{
var dtStartDate = this;
var dtEndDate = pdtEndDate;
if (dtStartDate.getDay() == 0 || dtStartDate.getDay() == 6) {iNumDays += 1;}
}
else
{
var dtStartDate = pdtEndDate;
var dtEndDate = this;
if (dtEndDate.getDay() == 0 || dtEndDate.getDay() == 6) {iNumDays += 1;}
}

for (var d = dtStartDate; d < dtEndDate; d.setDate(d.getDate() + 1))
{
var iDOW = d.getDay();

if (iDOW > 0 && iDOW < 6)
{
iNumDays++;
}
}

return iNumDays;
}
``````
CERTIFIED EXPERT

Commented:
With my minor addition to cater for the starting date being a weekend, the code works like a charm. Thanks again.

Lee
Software Engineer
CERTIFIED EXPERT

Commented:
Lee:  that is excellent news.  I'm glad to have been able to help.

Thanks for the grade & points.

Good luck & have a great day.
##### Thanks for using Experts Exchange.

• View three pieces of content (articles, solutions, posts, and videos)
• Ask the experts questions (counted toward content limit)
• Customize your dashboard and profile