Как рассчитать рабочее время между двумя датами, исключая праздничные и выходные дни?

1

Скажем, у меня две даты:

$initialDate = '08/10/2015 09:30:24 am';
$finalDate = '15/10/2015 15:47:38 pm';
$holiday = '12/10/2015';

Я должен рассмотреть час этих дней.

Hours to consider : 8 hours per day;
Start : 8 pm
End: 18 pm (24 hours format )
Lunch break start: 12:00 pm
Lunch break end: 14:00 pm

Example 1 : From 08/10/2015 10:00:00 to 09/10/2015 17:00:00 results 13 working hours. ( excludes lunch break )
Example 2 : From 08/10/2015 14:00:00 to 09/10/2015 18:00:00 results 12 working hours. ( Do not exclude 2 hours from begin date, because starts after 14:00 pm, lunch break )
Example 3 : From 08/10/2015 16:00:00 to 09/10/2015 18:00:00 results 10 working hours. ( Do not exclude 2 hours from begin date, because starts after 14:00 pmm lunch break )
Exampld 4 : From 08/10/2015 08:00:00 to 09/10/2015 11:00:00 results 14 working hours. ( Exclude 2 hours from begin date, and do not exclude 2 hours from end date, because isn't after 14:00 pm  )

И я должен рассчитать рабочее время и рабочие дни между этими двумя датами, за исключением выходных и праздничных дней, как я могу это сделать? Я использую PHP.

PS: У меня уже есть что-то, но без обеденного перерыва... Я сделал исследование здесь, на StackOverFlow.

Код:

function get_workdays($dataInicial,$dataFinal){
// arrays
$days_array = array();
$skipdays = array("Saturday", "Sunday");
$skipdates = get_feriados();

// other variables
$i = 0;
$current = $dataInicial;

if($current == $dataFinal) // same dates
{
    $timestamp = strtotime($dataInicial);
    if (!in_array(date("l", $timestamp), $skipdays)&&!in_array(date("Y-m-d", $timestamp), $skipdates)) {
        $days_array[] = date("Y-m-d",$timestamp);
    }
}
elseif($current < $dataFinal) // different dates
{
    while ($current < $dataFinal) {
        $timestamp = strtotime($dataInicial." +".$i." day");
        if (!in_array(date("l", $timestamp), $skipdays)&&!in_array(date("Y-m-d", $timestamp), $skipdates)) {
            $days_array[] = date("Y-m-d",$timestamp);
        }
        $current = date("Y-m-d",$timestamp);
        $i++;
    }
}
return $days_array;

 }

function get_feriados(){
$dateAno = Date('Y');
$days_array = array(
        $dateAno.'-10-12', // Padroeira do Brasil/ Dias das Crianças
        $dateAno.'-11-02',  // Finados
        $dateAno.'-12-25'  // Finados
);
return $days_array;

 }

date_default_timezone_set('America/Sao_Paulo');
$dateAno = Date('Y');
$dataInicial = Date('08/10/2015 H:i');
$dataFinal = Date('13/10/2015 H:i');

// timestamps
$from_timestamp = strtotime(str_replace('/', '-', $dataInicial));
$to_timestamp = strtotime(str_replace('/', '-', $dataFinal));

// work day seconds
$workday_start_hour = 9;
$workday_end_hour = 17;
$workday_seconds = ($workday_end_hour - $workday_start_hour)*3600;

// work days beetwen dates, minus 1 day
$from_date = date('Y-m-d',$from_timestamp);
$to_date = date('Y-m-d',$to_timestamp);

$workdays_number = count(get_workdays($from_date,$to_date))-1;
$workdays_number = $workdays_number<0 ? 0 : $workdays_number;

// start and end time
$start_time_in_seconds = date("H",$from_timestamp)*3600+date("i",$from_timestamp)*60;
$end_time_in_seconds = date("H",$to_timestamp)*3600+date("i",$to_timestamp)*60;

// final calculations
$working_hours = ($workdays_number * $workday_seconds + $end_time_in_seconds - $start_time_in_seconds) / 86400 * 24;

print_r('<br/> Horas úteis '.$working_hours);


}

Но не рассматривайте два часа перерыва на обед. Может кто-нибудь, пожалуйста, помогите мне?

  • 0
    Какие даты отпуска вы используете? Какие дни считаются для вас праздниками?
  • 0
    Я отредактировал свой вопрос ... Я из Бразилии, и скажем, что у меня два праздника: 12-10-2015 и 25-10-2015.
Показать ещё 5 комментариев
Теги:

4 ответа

1
Лучший ответ

Я ожидаю, что это сделает все, что вы хотите. Но я изменил формат даты и времени следующим образом. Проверь это. Используется меньше комментариев. Если какой-либо запрос, пожалуйста, спрашивайте. Праздники представляют собой массивы, добавляются и удаляются по мере необходимости.

Время с 12:00 до 14:00 обрабатывается. Время ниже 08:00 обрабатывается. Время над 18:00 обрабатывается.

<?php 
$initialDate =  '2015-10-13 08:15:00';    //start date and time in YMD format
$finalDate = '2015-10-14 11:00:00';    //end date and time in YMD format
$holiday = array('2015-10-12');   //holidays as array
$noofholiday  = sizeof($holiday);     //no of total holidays

//create all required date time objects
$firstdate = DateTime::createFromFormat('Y-m-d H:i:s',$initialDate);  
$lastdate = DateTime::createFromFormat('Y-m-d H:i:s',$finalDate);
if($lastdate > $firstdate)
{
$first = $firstdate->format('Y-m-d');
$first = DateTime::createFromFormat('Y-m-d H:i:s',$first." 00:00:00" );
$last = $lastdate->format('Y-m-d');
$last = DateTime::createFromFormat('Y-m-d H:i:s',$last." 23:59:59" );
$workhours = 0;   //working hours

for ($i = $first;$i<=$last;$i->modify('+1 day') )
{
    $holiday = false;
    for($k=0;$k<$noofholiday;$k++)   //excluding holidays
        {
        if($i == $holiday[$k])
            {
            $holiday = true;
            break;
        }   }
    $day =  $i->format('l');
    if($day === 'Saturday' || $day === 'Sunday')  //excluding saturday, sunday 
    $holiday = true;

    if(!$holiday)
    {   
        $ii = $i ->format('Y-m-d');
        $f = $firstdate->format('Y-m-d');
        $l = $lastdate->format('Y-m-d');
        if($l ==$f )
        $workhours +=sameday($firstdate,$lastdate);
        else if( $ii===$f)
        $workhours +=firstday($firstdate);
        else if ($l ===$ii)
        $workhours +=lastday($lastdate);
        else
        $workhours +=8;     
    }
}

echo $workhours;   //echo the hours
}
else
echo "lastdate less than first date";

function sameday($firstdate,$lastdate)
{
    $fmin = $firstdate->format('i');
    $fhour = $firstdate->format('H');
    $lmin = $lastdate->format('i');
    $lhour = $lastdate->format('H');
    if($fhour >=12 && $fhour <14)
    $fhour = 14;
    if($fhour <8)
    $fhour =8;
    if($fhour >=18)
    $fhour =18;
    if($lhour<8)
    $lhour=8;
    if($lhour>=12 && $lhour<14)
    $lhour = 14;
    if($lhour>=18)
    $lhour = 18;
    if($lmin == 0)
    $min = ((60-$fmin)/60)-1;
    else
    $min = ($lmin-$fmin)/60;
    return $lhour-$fhour + $min;
}

function firstday($firstdate)   //calculation of hours of first day
{
    $stmin = $firstdate->format('i');
    $sthour = $firstdate->format('H');
    if($sthour<8)   //time before morning 8
    $lochour = 8;
    else if($sthour>18)
    $lochour = 0;
    else if($sthour >=12 && $sthour<14)
    $lochour = 4;
    else
    {
    $lochour = 18-$sthour;
    if($sthour<=14)
    $lochour-=2;
    if($stmin == 0)
    $locmin =0;
    else    
    $locmin = 1-( (60-$stmin)/60);   //in hours
    $lochour -= $locmin;
    }
    return $lochour;
}

function lastday($lastdate)   //calculation of hours of last day
{
    $stmin = $lastdate->format('i');
    $sthour = $lastdate->format('H');
    if($sthour>=18)   //time after 18
    $lochour = 8;
    else if($sthour<8)   //time before morning 8
    $lochour = 0;
    else if($sthour >=12 && $sthour<14)
    $lochour = 4;
    else
    {
    $lochour = $sthour - 8;
    $locmin = $stmin/60;   //in hours
    if($sthour>14)
    $lochour-=2;
    $lochour += $locmin;
    }
    return $lochour;
}
?>
  • 0
    Спасибо за вашу помощь, подскажите, пожалуйста, почему между датами $ initialDate = '2015-10-08 08:00:00'; $ finalDate = '2015-10-15 18:00:00'; возвращает 41 рабочее время, а не 40 рабочих часов? Отлично, твой код.
  • 0
    С той же даты, что я вам сказал, возвращаемся теперь 42 рабочих часа. $ holiday = array ('2015-10-12');
Показать ещё 8 комментариев
3

Если вы используете PHP 5.3 или выше, вы можете сделать это:

$datefrom = DateTime::createFromFormat('d/m/Y', '08/10/2015');
$dateto = DateTime::createFromFormat('d/m/Y', '15/10/2015');
$interval = $datefrom->diff($dateto);
$days = intval($interval->format('%a'));

Также вы можете удалить праздники, если:

if ($datetime1->getTimestamp() < $holiday->getTimestamp() and $datetime2->getTimestamp() > $holiday->getTimestamp()) $days--;

Рассчитайте часы между двумя днями:

$datefrom = DateTime::createFromFormat('d/m/Y H:i:s', '08/10/2015 12:51:34');
$dateto = DateTime::createFromFormat('d/m/Y H:i:s', '15/10/2015 13:14:56');

$hours = intval($interval->format('%a')) * 24 + $interval->format('%h');

Вы можете рассчитать часы запуска суммы, а затем вычесть ее. Как игнорировать выходные дни или рассчитать дни игнорирования:

while($dateto->getTimestamp() > $datefrom->getTimestamp()) {
    if (in_array($datefrom->format('w'), array('0','6'))) $ignore_days += 1;
    $datefrom->modify('+1 day');
}
  • 0
    Прежде всего, спасибо за помощь ... Но я должен учитывать начальный час и конечный час дня. Пример: $ workday_start_hour = 9; $ break_lunch_start = 12; $ break_lunch_end = 14; $ workday_end_hour = 19; `
  • 0
    Я не понимаю, полностью понимаю, какие данные у вас есть ... и какие данные вы хотите рассчитать.
Показать ещё 3 комментария
1

Проверьте приведенный ниже код, который вернет количество рабочих дней

function number_of_working_days($from, $to) {
    $workingDays = [1, 2, 3, 4, 5];// date format =  (1 = Monday,2 = Tue, ...)
    $holidayDays = ['*-12-25', '*-02-14', '2015-12-23']; // variable and fixed holidays

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

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

echo number_of_working_days('2015-12-01', '2015-09-10');

Из этого вы можете легко вычислить количество рабочих часов.

  • 0
    Прежде всего, спасибо за помощь ... Но я должен учитывать время начала и окончания, исключая перерыв на обед (2 часа).
  • 1
    $ workingDays = number_of_working_days ('2015-12-01', '2015-09-10'); $ = $ Рабочих часов * Рабочие 8; $ LunchBreakHours = $ 2 * Рабочие; $ TotalTimeSpent = $ workingHours- $ lunchBreakHours;
Показать ещё 1 комментарий
0

Я создал для вас этот класс, который вы можете использовать. Для этого nesbot/carbon библиотека nesbot/carbon (http://carbon.nesbot.com/), и вы используете ее так:

$calc = new HoursCalculator(
    Carbon::createFromFormat("Y-m-d H:i", "2015-10-7 09:00"),
    Carbon::createFromFormat("Y-m-d H:i", "2015-10-14 18:00"),
    [
        "2015-10-13"
    ]
);

echo $calc->getHours();

Heres класс:

class HoursCalculator {

    const LUNCH_HOURS = 2;

    protected $start;

    protected $end;

    protected $holidays;

    protected $hoursTotal;

    public function __construct(Carbon $start, Carbon $end, $holidays = [])
    {
        $this->start = $start;
        $this->end = $end;
        $this->holidays = $holidays;
    }

    public function getHours()
    {
        $dayHours = $this->getHoursInADay();

        return $this->calculateHours($dayHours);
    }

    protected function getHoursInADay()
    {
        $start = $this->start;
        $end = Carbon::createFromFormat("Y-m-d H:i", $this->start->format("Y-m-d") . " " . $this->end->format("H:i"));

        return $start->diffInHours($end) - self::LUNCH_HOURS;
    }

    protected function getStartDate()
    {
        return $this->start->format('Y-m-d');
    }

    protected function calculateHours($hoursInDay)
    {
        $start = $this->start->copy()->startOfDay();
        $end = $this->end->copy()->endOfDay();
        $days = 0;

        while($start->lt($end)) {
            if (!$this->isHoliday($start) && !$this->isWeekend($start)) {
                $days++;
            }

            $start->addDay(1);
        }

        return $days * $hoursInDay;
    }

    protected function isHoliday(Carbon $date)
    {
        $date->startOfDay();

        foreach($this->holidays as $holiday) {
            $holiday = Carbon::createFromFormat("Y-m-d", $holiday)->startOfDay();

            if ($date->eq($holiday)) {
                return true;
            }
        }

        return false;
    }

    protected function isWeekend(Carbon $date)
    {
        return $date->isWeekend();
    }
}

Надеюсь это поможет!

  • 0
    Я попробую ваш код и дам вам отзыв. Это будет рассматривать примеры, которые я положил на мой первый пост? Час начинать до 14:00, чтобы исключить час обеда?
  • 0
    В классе вы устанавливаете, сколько часов обеда в const LUNCH_HOURS
Показать ещё 8 комментариев

Ещё вопросы

Сообщество Overcoder
Наверх
Меню