5

We have a PHP based timesheet system that's been developed in house, and has evolved over the years, however one piece of information presented to the users is the number of working days remaining on each project.

Currently, I simply take the difference between the current date and project end date, and divide by 7 and multiply by 5. This has sufficed for a long time and is mostly accurate enough for staff that work full time Monday to Friday. However, we now have a number of staff who work only the odd day a week.

The timesheet system is aware of what days which staff work, this information is stored in a string in the user class, for a full time worker, the value would be NNYYYYY (meaning ssMTWTF).

I could very easily make the result more accurate, by dividing the difference between the two dates by seven, and then multiplying by the number of days they work, but whilst making this change, I'm considering producing a much more accurate means of calculating the real value.

The easiest way that springs to mind would be to just use a loop between the two dates, comparing the day of the week to the user's working pattern, adding one to a counter on days where the user works that day.

Given that this calculation has to be performed on average about 30 times per page view due to the number of projects on the timesheet and projects can span 12 or 18 months at a time (that's a lot of looping for every page load), I'm wondering if there's a more efficient method of doing this in PHP?

Bryan
  • 3,224
  • 9
  • 41
  • 58
  • 2
    The task can be broken into three parts: the partial first week, some number of full weeks, the partial last week. The calculation that you're already doing works for the full weeks in the middle, so you only need a loop to handle the partial weeks. – user3386109 May 03 '14 at 13:38
  • Good idea @user3386109, I hadn't considered that approach at all. Maybe worth posting as an answer? – Bryan May 03 '14 at 13:41
  • I don't know if I would call that an answer, just something to think about. You still have a lot of details to work out :) – user3386109 May 03 '14 at 13:47
  • A detail blog: http://goo.gl/YOsfPX – Suresh Kamrushi Jan 20 '16 at 12:39

5 Answers5

10

May be this code snippet will help:

<?php
//get current month for example
$beginday = date("Y-m-01");
$lastday  = date("Y-m-t");

$nr_work_days = getWorkingDays($beginday, $lastday);
echo $nr_work_days;

function getWorkingDays($startDate, $endDate)
{
    $begin = strtotime($startDate);
    $end   = strtotime($endDate);
    if ($begin > $end) {
        echo "startdate is in the future! <br />";

        return 0;
    } else {
        $no_days  = 0;
        $weekends = 0;
        while ($begin <= $end) {
            $no_days++; // no of days in the given interval
            $what_day = date("N", $begin);
            if ($what_day > 5) { // 6 and 7 are weekend days
                $weekends++;
            };
            $begin += 86400; // +1 day
        };
        $working_days = $no_days - $weekends;

        return $working_days;
    }
}

Another solution can be: Get date range between two dates excluding weekends

Community
  • 1
  • 1
Samiul Amin Shanto
  • 1,397
  • 9
  • 19
2

You can find number of working days using below function.

Here you can see LIVE DEMO.

function number_of_working_days($startDate, $endDate)
{
    $workingDays = 0;
    $startTimestamp = strtotime($startDate);
    $endTimestamp = strtotime($endDate);
    for ($i = $startTimestamp; $i <= $endTimestamp; $i = $i + (60 * 60 * 24)) {
        if (date("N", $i) <= 5) $workingDays = $workingDays + 1;
    }
    return $workingDays;
}
Faisal
  • 4,591
  • 3
  • 40
  • 49
1

If you want to find the total working days between two date with weekdays option. Then this will help

        $startDate = '2016-10-01';
        $endDate =  '2016-10-31';
        $weekdays = array('1','2','3','4','5','6'); //this i think monday-saturday

        $begin = new DateTime($startDate);
        $end = new DateTime($endDate);

        $end = $end->modify( '+1 day' ); //add one day so as to include the end date of our range

        $interval = new DateInterval('P1D'); // 1 Day
        $dateRange = new DatePeriod($begin, $interval, $end);

        $total_days = 0;
        //this will calculate total days from monday to saturday in above date range
        foreach ($dateRange as $date) {

         if (in_array($date->format("N"),$weekdays)) {
                $total_days++; 
          }
        }
sanu
  • 1,048
  • 3
  • 14
  • 28
  • This is a neat solution but it doesn't explain what the $weekdays variable should contain and has unnecessary commented code. – Janne Annala Oct 26 '16 at 12:00
0

I tried some of the solutions and they did not work for me (gave me the result including weekends), so I wrote this as a solution:

function number_of_working_days($from, $to) {
    $target = strtotime($from);
    $days = 0;  
    while ($target < strtotime(date("Y-m-d",strtotime($to)))) {
        if(date("N",$target) <= 5) $days++;
        $target += (60*60*24);  /* move forward by 1 day */
    }
    return $days;
}

Where the $from and $to are dates from a mySQL table.

0
function workingDaysBetweenDates(startDate, endDate) {

    // Validate input
    if (endDate < startDate)
        return 0;

    // Calculate days between dates
    var millisecondsPerDay = 86400 * 1000; // Day in milliseconds
    startDate.setHours(0,0,0,1);  // Start just after midnight
    endDate.setHours(23,59,59,999);  // End just before midnight
    var diff = endDate - startDate;  // Milliseconds between datetime objects    
    var days = Math.ceil(diff / millisecondsPerDay);

    // Subtract two weekend days for every week in between
    var weeks = Math.floor(days / 7);
    days = days - (weeks * 2);

    // Handle special cases
    var startDay = startDate.getDay();
    var endDay = endDate.getDay();

    // Remove weekend not previously removed.   
    if (startDay - endDay > 1)         
        days = days - 2;      

    // Remove start day if span starts on Sunday but ends before Saturday
    if (startDay == 0 && endDay != 6) {
        days = days - 1;  
    }

    // Remove end day if span ends on Saturday but starts after Sunday
    if (endDay == 6 && startDay != 0) {
        days = days - 1;
    }

    return days;
}

$('#results').html(workingDaysBetweenDates(new Date('6/03/2019'), new Date('6/17/2019')));

Hope this helps.