A simple way to count business days between two dates in PHP

Philippe Lonchampt
code16
Published in
2 min readMay 22, 2018
Photo by rawpixel on Unsplash

With PHP, many of us are using nesbot/carbon to handle dates. Unfortunatly, there is no simple way with this package to handle closed periods, or holidays in days counting.

We at Code 16, had to perform such day counting for a equipement rental website. The need was:

  • a client can only choose, for rental dates, business days, meaning no weekend days and no holidays;
  • and to compute the rental duration, and some deadlines, we only count business days also.

We decided to built a tiny package for this, named carbon-business-days. Here’s how it should be used:

$date = new BusinessDays();$days = $date->daysBetween(
Carbon::createFromDate(2018, 1, 1), // This is a Monday
Carbon::createFromDate(2018, 1, 15)
);
// $days equals 10
// Set holidays
$date->addHoliday(Carbon::createFromDate(2018, 1, 1));
$days = $date->daysBetween(
Carbon::createFromDate(2018, 1, 1),
Carbon::createFromDate(2018, 1, 15)
);
// $days is now 9
// Set a closed period (whole 2nd week)
$date->addClosedPeriod(
Carbon::createFromDate(2018, 1, 8),
Carbon::createFromDate(2018, 1, 12)
);
$days = $date->daysBetween(
Carbon::createFromDate(2018, 1, 1),
Carbon::createFromDate(2018, 1, 15)
);
// $days is finally 5

You can also add or subtract days to a given date:

$newDate = $date->addDaysTo(
Carbon::createFromDate(2018, 5, 14),
10
);
$newDate = $date->subDaysFrom(
Carbon::createFromDate(2018, 5, 14),
10
);

For the purpose of our client’s project, we decided to declare BusinessDays as a singleton in the whole codebase (with Laravel’s Container singleton binding, but it could be achieve in many ways), where we applied holidays (from configuration—in fact the package come with a little help for French users), closed periods (from database filled by the client) and weekend days. From there, we wrote a global accessor, and voilà:

business_days()->daysBetween($rental->start_date, today());

And for a real code example, here’s a custom validation rule using the package:

class ValidRentStartDate implements Rule
{

public function passes($attribute, $value)
{
$date = Carbon::createFromFormat("Y-m-d", $value);

if(!business_days()->isOpenedDay($date)) {
return false;
}

return $date->between(
business_days()->addDaysTo(today(), config('min_business_days_from_now_to_rent_date')),
business_days()->addDaysTo(today(), config('max_business_days_from_now_to_rent_date'))
);
}
}

Simple, but useful!

--

--

Philippe Lonchampt
code16
Editor for

Developer and founder of Code 16, maintainer of Laravel Sharp.