Calculate working days between to dates
Asked Answered
G

5

7

I want to calculate the number of working days.

By using carbon I can calculate days and reduce weekends.

$num_days = $to_date->diffInWeekdays($from_date) + 1;

And I have an array of holidays, and I want to reduce the number of days if there is a holiday in between the days.

Is there any way to do this.

Thank you

Govern answered 4/1, 2017 at 11:11 Comment(1)
Are the dates in your holiday array just strings or Carbon instances? If they're strings how are they formatted?Stichous
S
13

You could use diffInDaysFiltered to achieve what you're after.

Assuming your holidays are an array of Carbon instances you could do something like:

$start = Carbon::now()->setDate(2014, 1, 1);
$end = Carbon::now()->setDate(2015, 1, 1);

$holidays = [
    Carbon::create(2014, 2, 2),
    Carbon::create(2014, 4, 17),
    Carbon::create(2014, 5, 19),
    Carbon::create(2014, 7, 3),
];

$days = $start->diffInDaysFiltered(function (Carbon $date) use ($holidays) {
    return $date->isWeekday() && !in_array($date, $holidays);
}, $end);

If it's just an array of strings then you could do something like:

!in_array($date->format('[the-format-of-your-dates]'), $holidays)
Stichous answered 4/1, 2017 at 11:33 Comment(3)
This is a nice and short way to do it. I just would add "false" as the third parameter of diffInDaysFiltered to get negative values for a past date. Otherwise you will get a positive value when the $end date is in the past or future. $days = $start->diffInDaysFiltered(function (Carbon $date) use ($holidays) { return $date->isWeekday() && !in_array($date, $holidays); }, $end,false);Lingle
This works fine, though it seems not to be skipping holidays. Please guide ThanksMendiola
@MasabaJamesMoses I'd recommend you create a new question as there are potentially far too many reasons why this might not be working for you.Stichous
H
6

Here is a small utility function to calculate working days:

function getWorkingDaysCount($from, $to) {
    $workingDays = [1, 2, 3, 4, 5];         // Working days (week days)
    $holidayDays = ['*-12-25', '*-01-01'];  // Holidays array, add desired dates to this array 

    $from = new DateTime($from);
    $to = new DateTime($to);
    $to->modify('+1 day');
    $interval = new DateInterval('P1D');
    $periods = new DatePeriod($from, $interval, $to);

    $days = 0;
    foreach ($periods as $period) {
      if (!in_array($period->format('N'), $workingDays)) continue;
      if (in_array($period->format('Y-m-d'), $holidayDays)) continue;
      if (in_array($period->format('*-m-d'), $holidayDays)) continue;
      $days++;
  }
  return $days;
}

You can pass the starting and end date to get the number of days.

Homogeneous answered 4/1, 2017 at 11:18 Comment(0)
L
3

You can take advantage of Carbon's diffInDaysFiltered() and isWeekend() methods. Below is a modified code from Carbon's documentation.

$daysForExtraCoding = $dt->diffInDaysFiltered(function(Carbon $date) {
   return !$date->isWeekend();
}, $dt2);

echo $daysForExtraCoding;      // 260

Shorter code

$daysForExtraCoding = $dt->diffInWeekdays($dt2);
Linette answered 18/10, 2020 at 15:1 Comment(0)
S
0

You can get this by following code

<?php
    function workdays($start,$end,$holidays){
        $end = strtotime($end);
        $start = strtotime($start);
        $days = ($end - $start) / 86400 + 1;

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

        $the_first_day_of_week = date("N", $start);
        $the_last_day_of_week = date("N", $end);

        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 {
            if ($the_first_day_of_week == 7) {
                $no_remaining_days--;

                if ($the_last_day_of_week == 6) {
                    $no_remaining_days--;
                }
            }
            else {
                $no_remaining_days -= 2;
            }
        }

       $workingDays = $no_full_weeks * 5;
        if ($no_remaining_days > 0 )
        {
          $workingDays += $no_remaining_days;
        }

        foreach($holidays as $holiday){
            $time_stamp=strtotime($holiday);
            if ($start <= $time_stamp && $time_stamp <= $end && date("N",$time_stamp) != 6 && date("N",$time_stamp) != 7)
                $workingDays--;
        }

        return $workingDays;
    }



    echo workdays("2016-01-04","2016-01-30",array("2016-01-25","2016-01-26","2016-01-27"))

    ?>
Sandrocottus answered 4/1, 2017 at 12:29 Comment(0)
L
0
function getWorkingDays($days1,$start_dt,$end_dt,$holidays) {


    $date1 = $start_dt;
    $date2 = $end_dt;

    $array = array();
    $query = $holidays;// pass array of holidays.
    foreach($query as $row)
    {
        $array[] = $row['h_date'];
    }

    $workingDays = [1, 2, 3, 4, 5];// 1 = Mon,...
    $holidayDays = $array; # variable and fixed holidays

    $from = new DateTime($date1);
    $to = new DateTime($date2);
    $to->modify('+1 day');
    $interval = new DateInterval('P1D');
    $periods = new DatePeriod($from, $interval, $to);

    $nameOfDay = date('N', strtotime($date1));
    if($nameOfDay==7)
    {
        $nameOfDay=0;
    }
    $days = $nameOfDay;
    $fullDate=explode('-',$date1);

    $y=$fullDate['0'];
    $m=$fullDate['1'];
    $d=$fullDate['2'];

    foreach ($periods as $period) {
        if (!in_array($period->format('N'), $workingDays)) {

            $d++;
            continue;
        }
        if (in_array($period->format('Y-m-d'), $holidayDays)) {
            if($d==32 && $m==12)
            {
                $d=1;
                $m=1;
                $y++;
            }

            $d++;
            continue;
        }
        if (in_array($period->format('*-m-d'), $holidayDays)) {

            $d++;
            continue;
        }

        switch ($m) {

            case '2':
                if( (0 == $y % 4) and (0 != $y % 100) or (0 == $y % 400) )
                {
                    if($d>=30)
                    {
                        $d=1;
                        $m++;
                        break;
                    }  
                }
                else
                {
                    if($d>=29)
                    {
                        $d=1;
                        $m++;
                        break;
                    }  
                }

            case '4':
            case '6':
            case '9':
            case '11':
                if($d>=31)
                {
                    $d=1;
                    $m++;
                }
                break;

            case '1':
            case '3':
            case '5':
            case '7':
            case '8':
            case '10':
                if($d>=32)
                {
                    $d=1;
                    $m++;   
                }
                break;

            case '12':
                if($d>=32)
                {
                    $d=1;
                    $m=1;
                    $y++;
                }
                break;
        }

        $dn = date('D', strtotime($d.'-'.$m.'-'.$y));
        if($d==1 && $dn=='Sun')
        {
            $d++;
        }
        if($d==1 && $dn=='Sat')
        {
            $d=$d+2;
        }

        $dayName = date('D', strtotime($d.'-'.$m.'-'.$y));

        $planbookid = $this->planbook->get_planbook_id();

        $d++;
        $days++;
    }
    echo json_encode($result);
}
Laurinda answered 31/3, 2018 at 5:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.