Cálculo de Hora
Pessoal estou utilizando a classe de cálculo de horas uteis do mod Gabriel, no entanto estou com um problema, chamados que foram abertos ou encerrados fora do expediente ou seja que a data inicial ou a data final está fora das horas uteis a classe não consegue realizar o cálculo.
Erro:
>
Data Inicial: 2014-06-16 15:53:41
Data Final: 2014-06-30 17:29:21
Fatal error: Call to undefined function RuntimeException() in /home/colhabon/public_html/intranet/admin/class/calc.php on line 199
Código de teste:
$manha = new Period();
$manha->addWorkday(CalendarDay::MONDAY)
->addWorkday(CalendarDay::TUESDAY)
->addWorkday(CalendarDay::WEDNESDAY)
->addWorkday(CalendarDay::THURSDAY)
->addWorkday(CalendarDay::FRIDAY)
->addWorkday(CalendarDay::SATURDAY);
$manha->setStart(DateTime::createFromFormat('H:i:s', '07:30:00'));
$manha->setEnd(DateTime::createFromFormat('H:i:s', '11:00:00'));
$tarde = new Period();$tarde->addWorkday(CalendarDay::MONDAY)
->addWorkday(CalendarDay::TUESDAY)
->addWorkday(CalendarDay::WEDNESDAY)
->addWorkday(CalendarDay::THURSDAY)
->addWorkday(CalendarDay::FRIDAY)
->addWorkday(CalendarDay::SATURDAY);
$tarde->setStart(DateTime::createFromFormat('H:i:s', '13:00:00'));
$tarde->setEnd(DateTime::createFromFormat('H:i:s', '16:45:00'));
$workPeriod = new WorkPeriod();$workPeriod->addPeriod($manha)
->addPeriod($tarde);
$data1 = "2014-06-16 15:53:41";$data2 = "2014-06-30 17:29:21";//Está fora do expediente que termina 16:45 - se o expediente acabasse 17:30:00 o cálculo funcionaria corretamente..
echo "Data Inicial: ".$data1."<br>";
echo "Data Final: ".$data2."<br>";
$periodo = $workPeriod->calculateWorkedDateInterval(new DateTime($data1), new DateTime($data2));
$teste = $periodo->format('%H:%I:%S');
echo "Resultado: ".$teste;
O correto seria me retornar as horas uteis fazendo o cálculo de 15:53:41 até 16:45:00 no entanto a classe não consegue calcular.
Classe:
<?php
/**
* Classe "enum" representa os dias da semana
* @author Gabriel Heming <gabriel.heming@hotmail.com>
**/
class CalendarDay {
const SUNDAY = 0;
const MONDAY = 1;
const TUESDAY = 2;
const WEDNESDAY = 3;
const THURSDAY = 4;
const FRIDAY = 5;
const SATURDAY = 6;
}
class Period {
private $start;
private $end;
private $workdayCollection = array();
public function setStart(DateTime $start) {
$this->start = $start;
}
public function setEnd(DateTime $end) {
$this->end = $end;
}
public function addWorkday($calendarDay) {
if(!in_array($calendarDay , $this->workdayCollection)) {
$this->workdayCollection[] = $calendarDay;
}
return $this;
}
public function getStart() {
return $this->start;
}
public function getEnd() {
return $this->end;
}
/**
* verifica se a hora está dentro do período infomado como trabalho
* @param DateTime $dateTime
* @return boolean
**/
public function isBetween(DateTime $dateTime) {
/** é necessária a conversão de dias pois a classe datetime carrega consigo os dias da semana **/
return (
$dateTime >= (new DateTime($dateTime->format('Y-m-d').' '.$this->start->format('H:i:s')))
&& $dateTime < (new DateTime($dateTime->format('Y-m-d').' '.$this->end->format('H:i:s')))
&& $this->isWorkDay($dateTime)
);
}
/**
* verifica se a data é de um dia de trabalho
* @param DateTime $dateTime
* @return boolean
**/
public function isWorkDay(DateTime $dateTime) {
return (in_array((int)$dateTime->format('w') , $this->workdayCollection));
}
/**
* calcula o tempo trabalhado dentro do período
* @param DateTime $dateTime
* @return DateInterval
**/
public function calculateWorkedDateInterval(DateTime $dateTimeStart , DateTime $dateTimeEnd) {
$start = new DateTime($dateTimeStart->format('Y-m-d').' '.$this->start->format('H:i:s'));
$end = new DateTime($dateTimeStart->format('Y-m-d').' '.$this->end->format('H:i:s'));
$started = $dateTimeStart > $start ? $dateTimeStart : $start;
$ended = $dateTimeEnd > $end ? $end : $dateTimeEnd;
return $started > $ended ? false : $started->diff($ended , true);
}
/**
* Usado apenas para ordenação dos períodos
* para sempre manter uma ordem "crescent"
* @param Period $period
* @return boolean
**/
public static function isEarlierThan(Period $period1 , Period $period2) {
return $period1->getStart() > $period2->getStart();
}
}
class WorkPeriod {
private $period = array();
public function addPeriod(Period $period) {
$this->period[] = $period;
/** reeordena o array para manter a ordem de períodos **/
usort($this->period , array('Period' , 'isEarlierThan'));
return $this;
}
public function isWorkDay($dateTime) {
foreach($this->period AS $period) {
if($period->isWorkDay($dateTime)) {
return true;
}
}
return false;
}
/**
* calcula o tempo trabalhado dentro do período
* @param DateTime $start
* @param DateTime $end
* @return DateInterval
**/
public function calculateWorkedDateInterval($start , $end) {
if($start == $end) {
return $start->diff($end , true);
} else if ($start > $end) {
throw new RuntimeException('Cannot calculate worked period');
}
/** variáveis auxiliar **/
$estimatedDateInterval = $start->diff($end , true);//diferença entre a data de início e a data de entrada
$isAfterWorkTime = false;//se é um horário após o expediente
$dateTimeStartWork = null;//Data de início do trabalho
$date = new DateTime();//Cria um dateInterval zerado;
$zeroDateInterval = $date->diff($date , true);
if($this->isWorkDay($start)) {
foreach($this->period AS $period) {
if($period->isBetween($start)) {
$dateInterval = $period->calculateWorkedDateInterval($start , $end);
if(!$dateInterval instanceof DateInterval) {
return $zeroDateInterval;
}
$date1 = clone $date2 = new \DateTime();
$date1->add($estimatedDateInterval);
$date2->add($dateInterval);
if($date1 <= $date2) {
return $this->sumDateInterval($dateInterval , $zeroDateInterval);
} else {
try {
return $this->sumDateInterval(
$this->calculateWorkedDateInterval($start->add($dateInterval) , $end),
$dateInterval
);
} catch (RuntimeException $exception) {
return $zeroDateInterval;
}
}
} else {
$dateStartWork = new DateTime($start->format('Y-m-d').' '.$period->getStart()->format('H:i:s'));
if($dateStartWork >= $start) {
if(is_null($dateTimeStartWork)) {
$dateTimeStartWork = $dateStartWork;
} else {
$dateTimeStartWork = $dateStartWork < $dateTimeStartWork ? $dateStartWork : $dateTimeStartWork;
}
} else {
$isAfterWorkTime = true;
}
}
}
}
if(!is_null($dateTimeStartWork)) {
try {
return $this->sumDateInterval($this->calculateWorkedDateInterval($dateTimeStartWork , $end) , $zeroDateInterval);
} catch (RuntimeException $exception) {
return $zeroDateInterval;
}
}
if(!$this->isWorkDay($start) || $isAfterWorkTime) {
$start = $this->goToNextDay($start);
if($end >= $start) {
try {
return $this->sumDateInterval($this->calculateWorkedDateInterval($start , $end) , $zeroDateInterval);
} catch (RuntimeException $exception) {
return $zeroDateInterval;
}
} else {
return RuntimeException('Cannot calculate worked period');
}
}
}
private function goToNextDay(\DateTime $dateTime) {
$dateTime->add(new DateInterval('P1D'));
return (new DateTime($dateTime->format('Y-m-d 00:00:00')));
}
/**
* soma N dateIntervals
* @param DateInterval $augend
* @param DateInterval $addend
* @param DateInterval $_,...
* @return DateInterval
**/
private static function sumDateInterval(DateInterval $augend , DateInterval $addend , DateInterval $_ = null) {
$start = clone $end = new \DateTime();
$numArgs = func_num_args();
$addend = func_get_args();
for($i = 0 ; $i < $numArgs ; $i++) {
$end->add($addend[$i]);
}
return $end->diff($start , true);
}
}Discussão (1)
Carregando comentários...