Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <?php
- /**
- * Classe "enum" representa os dias da semana
- * @author Gabriel Heming <[email protected]>
- **/
- 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);
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment