# php – Day difference without weekends-ThrowExceptions

Exception or error:

I want to count the total day difference from user input

For example when the user inputs

`start_date = 2012-09-06` and `end-date = 2012-09-11`

For now I am using this code to find the diffeence

``````\$count = abs(strtotime(\$start_date) - strtotime(\$end_date));
\$day   = \$count+86400;
\$total = floor(\$day/(60*60*24));
``````

The result of total will be 6. But the problem is that I dont want to include the days at weekend (Saturday and Sunday)

``````2012-09-06
2012-09-07
2012-09-08 Saturday
2012-09-09 Sunday
2012-09-10
2012-09-11
``````

So the result will be 4

—-update—

I have a table that contains date,the table name is holiday date

for example the table contains `2012-09-07`

So, the total day will be 3, because it didn’t count the holiday date

how do I do that to equate the date from input to date in table?

How to solve:

Very easy with my favourites: `DateTime`, `DateInterval` and `DatePeriod`

``````\$start = new DateTime('2012-09-06');
\$end = new DateTime('2012-09-11');
// otherwise the  end date is excluded (bug?)
\$end->modify('+1 day');

\$interval = \$end->diff(\$start);

// total days
\$days = \$interval->days;

// create an iterateable period of date (P1D equates to 1 day)
\$period = new DatePeriod(\$start, new DateInterval('P1D'), \$end);

// best stored as array, so you can add more than one
\$holidays = array('2012-09-07');

foreach(\$period as \$dt) {
\$curr = \$dt->format('D');

// substract if Saturday or Sunday
if (\$curr == 'Sat' || \$curr == 'Sun') {
\$days--;
}

// (optional) for the updated question
elseif (in_array(\$dt->format('Y-m-d'), \$holidays)) {
\$days--;
}
}

echo \$days; // 4
``````

In my case I needed the same answer as OP, but wanted something a little smaller. @Bojan’s answer worked, but I didn’t like that it doesn’t work with `DateTime` objects, required using timestamps, and was comparing against `strings` instead of the actual objects themselves (which feels hacky)… Here’s a revised version of his answer.

``````function getWeekdayDifference(\DateTime \$startDate, \DateTime \$endDate)
{
\$days = 0;

while(\$startDate->diff(\$endDate)->days > 0) {
\$days += \$startDate->format('N') < 6 ? 1 : 0;
}

return \$days;
}
``````

Per @xzdead’s comment if you’d like this to be inclusive of the start and end date:

``````function getWeekdayDifference(\DateTime \$startDate, \DateTime \$endDate)
{
\$isWeekday = function (\DateTime \$date) {
return \$date->format('N') < 6;
};

\$days = \$isWeekday(\$endDate) ? 1 : 0;

while(\$startDate->diff(\$endDate)->days > 0) {
\$days += \$isWeekday(\$startDate) ? 1 : 0;
}

return \$days;
}
``````

use `DateTime`:

``````\$datetime1 = new DateTime('2012-09-06');
\$datetime2 = new DateTime('2012-09-11');
\$interval = \$datetime1->diff(\$datetime2);
\$woweekends = 0;
for(\$i=0; \$i<=\$interval->d; \$i++){
\$datetime1->modify('+1 day');
\$weekday = \$datetime1->format('w');

if(\$weekday !== "0" && \$weekday !== "6"){ // 0 for Sunday and 6 for Saturday
\$woweekends++;
}

}

echo \$woweekends." days without weekend";

// 4 days without weekends
``````

The easiest and fastest way to get difference without weekends is by using Carbon library.

Here’s an example how to use it:

``````<?php

\$from = Carbon\Carbon::parse('2016-05-21 22:00:00');
\$to = Carbon\Carbon::parse('2016-05-21 22:00:00');
echo \$to->diffInWeekdays(\$from);
``````

date(‘N’) gets the day of the week (1 – Monday, 7 – Sunday)

``````\$start = strtotime('2012-08-06');
\$end = strtotime('2012-09-06');

\$count = 0;

while(date('Y-m-d', \$start) < date('Y-m-d', \$end)){
\$count += date('N', \$start) < 6 ? 1 : 0;
\$start = strtotime("+1 day", \$start);
}

echo \$count;
``````

Have a look at this post:

(In your case, you could leave out the ‘holidays’ part since you’re after working/business days only)

``````<?php
//The function returns the no. of business days between two dates
function getWorkingDays(\$startDate,\$endDate){
// do strtotime calculations just once
\$endDate = strtotime(\$endDate);
\$startDate = strtotime(\$startDate);

//The total number of days between the two dates. We compute the no. of seconds and divide it to 60*60*24
//We add one to inlude both dates in the interval.
\$days = (\$endDate - \$startDate) / 86400 + 1;

\$no_full_weeks = floor(\$days / 7);
\$no_remaining_days = fmod(\$days, 7);

//It will return 1 if it's Monday,.. ,7 for Sunday
\$the_first_day_of_week = date("N", \$startDate);
\$the_last_day_of_week = date("N", \$endDate);

//---->The two can be equal in leap years when february has 29 days, the equal sign is added here
//In the first case the whole interval is within a week, in the second case the interval falls in two weeks.
if (\$the_first_day_of_week <= \$the_last_day_of_week) {
if (\$the_first_day_of_week <= 6 && 6 <= \$the_last_day_of_week) \$no_remaining_days--;
if (\$the_first_day_of_week <= 7 && 7 <= \$the_last_day_of_week) \$no_remaining_days--;
}
else {
// (edit by Tokes to fix an edge case where the start day was a Sunday
// and the end day was NOT a Saturday)

// the day of the week for start is later than the day of the week for end
if (\$the_first_day_of_week == 7) {
// if the start date is a Sunday, then we definitely subtract 1 day
\$no_remaining_days--;

if (\$the_last_day_of_week == 6) {
// if the end date is a Saturday, then we subtract another day
\$no_remaining_days--;
}
}
else {
// the start date was a Saturday (or earlier), and the end date was (Mon..Fri)
// so we skip an entire weekend and subtract 2 days
\$no_remaining_days -= 2;
}
}

//The no. of business days is: (number of weeks between the two dates) * (5 working days) + the remainder
//---->february in none leap years gave a remainder of 0 but still calculated weekends between first and last day, this is one way to fix it
\$workingDays = \$no_full_weeks * 5;
if (\$no_remaining_days > 0 )
{
\$workingDays += \$no_remaining_days;
}

return \$workingDays;
}

// This will return 4
echo getWorkingDays("2012-09-06","2012-09-11");
?>
``````

If you don’t need full days but accurate seconds instead try this code. This accepts unix timestamps as an input.

``````function timeDifferenceWithoutWeekends(\$from, \$to) {
\$start = new DateTime("@".\$from);
\$current = clone \$start;
\$end = new DateTime("@".\$to);
\$sum = 0;
while (\$current<\$end) {
\$endSlice = clone \$current;
\$endSlice->setTime(0,0,0);
\$endSlice->modify('+1 day');
if (\$endSlice>\$end) {
\$endSlice= clone \$end;
}
\$seconds = \$endSlice->getTimestamp()-\$current->getTimestamp();
\$currentDay = \$current->format("D");
if (\$currentDay != 'Sat' && \$currentDay != 'Sun') {
\$sum+=\$seconds;
}
\$current = \$endSlice;
}
return \$sum;
}
``````

``````/**
* Getting the Weekdays count[ Excludes : Weekends]
*
* @param type \$fromDateTimestamp
* @param type \$toDateTimestamp
* @return int
*/
public static function getWeekDaysCount(\$fromDateTimestamp = null, \$toDateTimestamp=null) {

\$startDateString   = date('Y-m-d', \$fromDateTimestamp);
\$timestampTomorrow = strtotime('+1 day', \$toDateTimestamp);
\$endDateString     = date("Y-m-d", \$timestampTomorrow);
\$objStartDate      = new \DateTime(\$startDateString);    //intialize start date
\$objEndDate        = new \DateTime(\$endDateString);    //initialize end date
\$interval          = new \DateInterval('P1D');    // set the interval as 1 day
\$dateRange         = new \DatePeriod(\$objStartDate, \$interval, \$objEndDate);

\$count = 0;

foreach (\$dateRange as \$eachDate) {
if (    \$eachDate->format("w") != 6
&&  \$eachDate->format("w") != 0
) {
++\$count;
}
}
return \$count;
}
``````

Here’s an alternative to calculate business days between two dates and also excludes USA holidays using Pear’s Date_Holidays from http://pear.php.net/package/Date_Holidays.

\$start_date and \$end_date should be DateTime objects (you can use `new DateTime('@'.\$timestamp)` to convert from timestamp to DateTime object).

``````<?php
{
require_once 'Date/Holidays.php';
\$dholidays = &Date_Holidays::factory('USA');
\$days = 0;

\$period = new DatePeriod(\$start_date, new DateInterval('P1D'), \$end_date);

foreach(\$period as \$dt)
{
\$curr = \$dt->format('D');

if(\$curr != 'Sat' && \$curr != 'Sun' && !\$dholidays->isHoliday(\$dt->format('Y-m-d')))
{
\$days++;
}
}
return \$days;
}
?>
``````