Guest User

By Gabriel

a guest
Aug 28th, 2014
227
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 7.86 KB | None | 0 0
  1. <?php
  2. /**
  3.  * Classe "enum" representa os dias da semana
  4.  * @author Gabriel Heming <[email protected]>
  5.  **/
  6. class CalendarDay {    
  7.     const SUNDAY = 0;
  8.     const MONDAY = 1;
  9.     const TUESDAY = 2;
  10.     const WEDNESDAY = 3;
  11.     const THURSDAY = 4;
  12.     const FRIDAY = 5;
  13.     const SATURDAY = 6;
  14. }
  15.  
  16. class Period {
  17.    
  18.     private $start;
  19.     private $end;
  20.     private $workdayCollection = array();
  21.    
  22.     public function setStart(DateTime $start) {
  23.         $this->start = $start;
  24.     }
  25.    
  26.     public function setEnd(DateTime $end) {
  27.         $this->end = $end;
  28.     }
  29.    
  30.     public function addWorkday($calendarDay) {
  31.         if(!in_array($calendarDay , $this->workdayCollection)) {
  32.             $this->workdayCollection[] = $calendarDay;
  33.         }
  34.        
  35.         return $this;
  36.     }
  37.    
  38.     public function getStart() {
  39.         return $this->start;
  40.     }
  41.    
  42.     public function getEnd() {
  43.         return $this->end;        
  44.     }
  45.    
  46.     /**
  47.      * verifica se a hora está dentro do período infomado como trabalho
  48.      * @param DateTime $dateTime
  49.      * @return boolean
  50.      **/
  51.     public function isBetween(DateTime $dateTime) {
  52.         /** é necessária a conversão de dias pois a classe datetime carrega consigo os dias da semana **/
  53.         return (
  54.             $dateTime >= (new DateTime($dateTime->format('Y-m-d').' '.$this->start->format('H:i:s')))
  55.             && $dateTime < (new DateTime($dateTime->format('Y-m-d').' '.$this->end->format('H:i:s')))
  56.             && $this->isWorkDay($dateTime)
  57.         );
  58.     }
  59.    
  60.     /**
  61.      * verifica se a data é de um dia de trabalho
  62.      * @param DateTime $dateTime
  63.      * @return boolean
  64.      **/
  65.     public function isWorkDay(DateTime $dateTime) {
  66.         return (in_array((int)$dateTime->format('w') , $this->workdayCollection));
  67.     }
  68.    
  69.     /**
  70.      * calcula o tempo trabalhado dentro do período
  71.      * @param DateTime $dateTime
  72.      * @return DateInterval
  73.      **/
  74.     public function calculateWorkedDateInterval(DateTime $dateTimeStart , DateTime $dateTimeEnd) {
  75.         $start = new DateTime($dateTimeStart->format('Y-m-d').' '.$this->start->format('H:i:s'));
  76.         $end = new DateTime($dateTimeStart->format('Y-m-d').' '.$this->end->format('H:i:s'));
  77.        
  78.         $started = $dateTimeStart > $start  ? $dateTimeStart : $start;
  79.         $ended = $dateTimeEnd > $end  ? $end : $dateTimeEnd;
  80.        
  81.         return $started > $ended ? false : $started->diff($ended , true);
  82.     }
  83.    
  84.     /**
  85.      * Usado apenas para ordenação dos períodos
  86.      * para sempre manter uma ordem "crescent"
  87.      * @param Period $period
  88.      * @return boolean
  89.      **/
  90.     public static function isEarlierThan(Period $period1 , Period $period2) {
  91.         return $period1->getStart() > $period2->getStart();
  92.     }
  93. }
  94.  
  95. class WorkPeriod {
  96.    
  97.     private $period = array();
  98.    
  99.     public function addPeriod(Period $period) {
  100.         $this->period[] = $period;
  101.        
  102.         /** reeordena o array para manter a ordem de períodos **/
  103.         usort($this->period , array('Period' , 'isEarlierThan'));
  104.                
  105.         return $this;
  106.     }
  107.    
  108.     public function isWorkDay($dateTime) {
  109.         foreach($this->period AS $period) {
  110.             if($period->isWorkDay($dateTime)) {
  111.                 return true;
  112.             }
  113.         }
  114.        
  115.         return false;        
  116.     }    
  117.    
  118.     /**
  119.      * calcula o tempo trabalhado dentro do período
  120.      * @param DateTime $start
  121.      * @param DateTime $end
  122.      * @return DateInterval
  123.      **/
  124.     public function calculateWorkedDateInterval($start , $end) {        
  125.         if($start == $end) {            
  126.             return $start->diff($end , true);
  127.         } else if ($start > $end) {
  128.             throw new RuntimeException('Cannot calculate worked period');
  129.         }
  130.        
  131.         /** variáveis auxiliar **/
  132.        
  133.         $estimatedDateInterval = $start->diff($end , true);//diferença entre a data de início e a data de entrada
  134.         $isAfterWorkTime = false;//se é um horário após o expediente
  135.         $dateTimeStartWork = null;//Data de início do trabalho
  136.        
  137.         $date = new DateTime();//Cria um dateInterval zerado;
  138.         $zeroDateInterval = $date->diff($date , true);
  139.                
  140.         if($this->isWorkDay($start)) {
  141.            
  142.             foreach($this->period AS $period) {
  143.                 if($period->isBetween($start)) {
  144.                     $dateInterval = $period->calculateWorkedDateInterval($start , $end);
  145.                     if(!$dateInterval instanceof DateInterval) {
  146.                         return $zeroDateInterval;
  147.                     }
  148.                    
  149.                     $date1 = clone $date2 = new \DateTime();
  150.                     $date1->add($estimatedDateInterval);
  151.                     $date2->add($dateInterval);
  152.                                        
  153.                     if($date1 <= $date2) {                        
  154.                         return $this->sumDateInterval($dateInterval , $zeroDateInterval);
  155.                     } else {
  156.                         try {
  157.                             return $this->sumDateInterval(
  158.                                 $this->calculateWorkedDateInterval($start->add($dateInterval) , $end),
  159.                                 $dateInterval
  160.                             );
  161.                         } catch (RuntimeException $exception) {
  162.                             return $zeroDateInterval;
  163.                         }
  164.                     }
  165.                 } else {    
  166.                     $dateStartWork = new DateTime($start->format('Y-m-d').' '.$period->getStart()->format('H:i:s'));
  167.                    
  168.                     if($dateStartWork >= $start) {
  169.                         if(is_null($dateTimeStartWork)) {
  170.                             $dateTimeStartWork = $dateStartWork;
  171.                         } else {
  172.                             $dateTimeStartWork = $dateStartWork < $dateTimeStartWork ? $dateStartWork : $dateTimeStartWork;
  173.                         }
  174.                     } else {
  175.                         $isAfterWorkTime = true;                          
  176.                     }
  177.                 }
  178.             }
  179.         }
  180.            
  181.         if(!is_null($dateTimeStartWork)) {
  182.             try {
  183.                 return $this->sumDateInterval($this->calculateWorkedDateInterval($dateTimeStartWork  , $end) , $zeroDateInterval);
  184.             } catch (RuntimeException $exception) {
  185.                 return $zeroDateInterval;
  186.             }
  187.         }
  188.        
  189.         if(!$this->isWorkDay($start) || $isAfterWorkTime) {
  190.             $start = $this->goToNextDay($start);
  191.            
  192.             if($end >= $start) {
  193.                 try {
  194.                     return $this->sumDateInterval($this->calculateWorkedDateInterval($start , $end) , $zeroDateInterval);
  195.                 } catch (RuntimeException $exception) {
  196.                     return $zeroDateInterval;
  197.                 }
  198.             } else {
  199.                 return RuntimeException('Cannot calculate worked period');
  200.             }
  201.         }
  202.     }
  203.    
  204.     private function goToNextDay(\DateTime $dateTime) {      
  205.         $dateTime->add(new DateInterval('P1D'));
  206.         return (new DateTime($dateTime->format('Y-m-d 00:00:00')));
  207.     }
  208.    
  209.     /**
  210.      * soma N dateIntervals
  211.      * @param DateInterval $augend
  212.      * @param DateInterval $addend
  213.      * @param DateInterval $_,...
  214.      * @return DateInterval
  215.      **/
  216.     private static function sumDateInterval(DateInterval $augend , DateInterval $addend , DateInterval $_ = null) {
  217.         $start = clone $end = new \DateTime();
  218.        
  219.         $numArgs = func_num_args();
  220.         $addend = func_get_args();
  221.        
  222.         for($i = 0 ; $i < $numArgs ; $i++) {
  223.             $end->add($addend[$i]);
  224.         }
  225.        
  226.         return $end->diff($start , true);
  227.     }
  228. }
Advertisement
Add Comment
Please, Sign In to add comment