Counting Work Days
I was working my way mentally through a little side project for work this morning, and I came up with an interesting puzzle: How can you compute the number of workdays left between two dates?
The purpose of this is mostly to help estimate projects by figuring out the amount of time left before project completion, and then dividing the estimated hours of workload over that amount of time. This could be helpful in planning out individual days, knowing how to ration out a day's worth of hours depending on how much time is left for various projects.
The trick with counting available days lies mostly in knowing what days aren't available. Since this is just an estimation tool, I'm not going to worry about vacation days or holidays. Knowing that, it's relatively trivial to start off with the absolute number of days between two dates using PHP:
// $start_date and $end_date are timestamps
define('SECONDS_IN_DAY', 86400);
$total_days_between = ceil(($date_end - $date_start) / SECONDS_IN_DAY);
PHP 5.3's DatTime and DateInterval classes make this even easier, but our target platform is only 5.2.8, and those classes aren't fully available according to the PHP documentation.
What we need to do is account for what weekdays the start and end dates are so that we can subtract the weekends from the total value.
First, I'll push start dates that are on a weekend forward to the next Monday, and end dates on the weekend to the previous Friday.
// Reduce units to days from seconds
$start_date = floor($start_date / SECONDS_IN_DAY);
$end_date = ceil($end_date / SECONDS_IN_DAY);
// Push the start date forward
do {
$start_info = getdate($start_date);
$start_date += 1;
} while ($start_info['wday'] 1 || $start_info['wday'] > 5);
$start_date -= 1;
// Push the end date forward
do {
$end_info = getdate($end_date);
$end_date -= 1;
} while ($end_info['wday'] 1 || $end_info['wday'] > 5);
$end_date += 1;
My thinking here is that computers are better at integer math than they are at conditions. Rather than saying "if()" something, I'm just adding a day to the date regardless, and then removing it when it's not needed.
With the above code, I have the start day and end day both on weekdays, not weekends. Then all I need is to remove the weekend days from the total count:
// Get the total days between the two dates
$days_between = ceil($end_date - $start_date);
// Get the number of weekends between
$weekends_between = floor(($end_date - $start_date) / 7);
// Remove the weekend days from the full count
$workdays_between -= $weekends_between * 2;
The above is pretty straightforward. For every 7 days - a week - there is one weekend, and for each weekend, remove two days from the count. Our total $workdays_between shows a reasonably accurate estimate of the number of work days between the start and end dates.