diff --git a/workflow/engine/classes/class.dates.php b/workflow/engine/classes/class.dates.php index d1ff56fd1..5d9dea6da 100755 --- a/workflow/engine/classes/class.dates.php +++ b/workflow/engine/classes/class.dates.php @@ -1,7 +1,8 @@ . + * along with this program. If not, see . * * For more information, contact Colosa Inc, 2566 Le Jeune Rd., * Coral Gables, FL, 33134, USA, or email info@colosa.com. * / - -/* + * + * /* * Created on 21/01/2008 * This class is used for handling dates * * @author David Callizaya */ - - require_once ( "classes/model/TaskPeer.php" ); - require_once ( "classes/model/HolidayPeer.php" ); - - /** - * @package workflow.engine.classes - */ -class dates { - private $holidays = array(); - private $weekends = array(); - private $range = array(); - private $skipEveryYear = true; - private $calendarDays = false; //by default we are using working days - private $hoursPerDay = 8; //you should change this - - - /** - * Function that calculate a final date based on $sInitDate and $iDuration - * This function also uses a Calendar component (class.calendar.php) where all the definition of - * a User, task, Process or default calendar is defined. base on that information is possible to setup different calendars - * and apply them to a task, process or user. Each calendar have Working Days, Business Hours and Holidays - * - * @name calculateDate - * @access public - * @author Hugo Loza - * @param date $sInitDate - * @param double $iDuration - * @param string $sTimeUnit - * @param string $iTypeDay - * @param string $UsrUid - * @param string $ProUid - * @param string $TasUid - * @return array('DUE_DATE'=>'Final calculated date formatted as Y-m-d H:i:s','DUE_DATE_SECONDS'=>'Final calculated date in seconds','OLD_DUE_DATE'=>'Using deprecate4d function','OLD_DUE_DATE_SECONDS'=>'Using deprecated function','DUE_DATE_LOG'=>'Log of all the calculations made') - * @todo test this function with negative durations (for events) - * - * - */ - function calculateDate( $sInitDate, $iDuration, $sTimeUnit, $iTypeDay, $UsrUid = NULL, $ProUid = NULL, $TasUid =NULL ) - { - //$oldDate=$this->calculateDate_noCalendar( $sInitDate, $iDuration, $sTimeUnit, $iTypeDay, $UsrUid, $ProUid, $TasUid); - //Set Calendar when the object is instanced in this order/priority (Task, User, Process, Default) - G::LoadClass('calendar'); - $calendarObj=new calendar($UsrUid,$ProUid,$TasUid); - //Get next Business Hours/Range based on : - switch(strtoupper($sTimeUnit)){ - case 'DAYS': $hoursToProcess=$iDuration*8; break;//In Hours - default: $hoursToProcess=$iDuration; break;//In Hours - } - $dateArray = explode(" ",$sInitDate); - $currentDate = $dateArray[0]; - $currentTime = isset($dateArray[1])? $dateArray[1]: "00:00:00"; - - $startTime=(float) array_sum(explode(' ',microtime())); - - $calendarObj->addCalendarLog("* Starting at: $startTime"); - $calendarObj->addCalendarLog(">>>>> Hours to Process: $hoursToProcess"); - $calendarObj->addCalendarLog(">>>>> Current Date: $currentDate"); - $calendarObj->addCalendarLog(">>>>> Current Time: $currentTime"); - $array_hours = explode(":",$currentTime); - $seconds2 = $array_hours[2]; - $minutes2 = 0; - while($hoursToProcess>0){ - $validBusinessHour=$calendarObj->getNextValidBusinessHoursRange($currentDate,$currentTime); - //For Date/Time operations - $currentDateA = explode("-",$validBusinessHour['DATE']); - $currentTimeA = explode(":",$validBusinessHour['TIME']); - $hour = $currentTimeA[0]; - $minute = $currentTimeA[1]; - $second = isset($currentTimeA[2])?$currentTimeA[2]:0; - $month = $currentDateA[1]; - $day = $currentDateA[2]; - $year = $currentDateA[0]; - $normalizedDate = date("Y-m-d H:i:s",mktime($hour,$minute,$second,$month,$day,$year)); - $normalizedDateInt = mktime($hour,$minute,$second,$month,$day,$year); - $normalizedDateSeconds = ($hour*60*60)+($minute*60); - $arrayHour = explode(".",$hoursToProcess); - if(isset($arrayHour[1])){ - $minutes1 = $arrayHour[1]; - $cadm = strlen($minutes1); - $minutes2 = (($minutes1/pow(10,$cadm))*60); - } - $possibleTime=date("Y-m-d H:i:s",mktime($hour+$hoursToProcess,$minute+$minutes2,$second+$seconds2,$month,$day,$year)); - $possibleTimeInt=mktime($hour+$hoursToProcess,$minute+$minutes2,$second+$seconds2,$month,$day,$year); - $offsetPermitedMinutes="0"; - $calendarBusinessEndA=explode(":",$validBusinessHour['BUSINESS_HOURS']['CALENDAR_BUSINESS_END']); - $calendarBusinessEndNormalized=date("Y-m-d H:i:s",mktime($calendarBusinessEndA[0],$calendarBusinessEndA[1]+$offsetPermitedMinutes,0,$month,$day,$year)); - $calendarBusinessEndInt=mktime($calendarBusinessEndA[0],$calendarBusinessEndA[1]+$offsetPermitedMinutes,0,$month,$day,$year); - $calendarBusinessEndSeconds=($calendarBusinessEndA[0]*60*60)+($calendarBusinessEndA[1]*60); - $calendarObj->addCalendarLog("Possible time: $possibleTime"); - $calendarObj->addCalendarLog("Current Start Date/Time: $normalizedDate"); - $calendarObj->addCalendarLog("Calendar Business End: $calendarBusinessEndNormalized"); - if($possibleTimeInt>$calendarBusinessEndInt){ - $currentDateTimeB = explode(" ",$calendarBusinessEndNormalized); - $currentDate = $currentDateTimeB[0]; - $currentTime = $currentDateTimeB[1]; - $diff = abs($normalizedDateSeconds-$calendarBusinessEndSeconds); - $diffHours = $diff/3600; - $hoursToProcess = $hoursToProcess-$diffHours; - } - else{ - $currentDateTimeA = explode(" ",$possibleTime); - $currentDate = $currentDateTimeA[0]; - $currentTime = $currentDateTimeA[1]; - $hoursToProcess = 0; - } - $calendarObj->addCalendarLog("** Hours to Process: $hoursToProcess"); - } - $calendarObj->addCalendarLog("+++++++++++ Calculated Due Date $currentDate $currentTime"); - $result['DUE_DATE'] = $currentDate." ".$currentTime; - $result['DUE_DATE_SECONDS'] = strtotime($currentDate." ".$currentTime); - //$result['OLD_DUE_DATE'] = date("Y-m-d H:i:s",$oldDate); - //$result['OLD_DUE_DATE_SECONDS']= $oldDate; - - $endTime=(float) array_sum(explode(' ',microtime())); - $calendarObj->addCalendarLog("* Ending at: $endTime"); - $calcTime=round($endTime-$startTime,3); - $calendarObj->addCalendarLog("** Processing time: ". sprintf("%.4f", ($endTime-$startTime))." seconds"); - $result['DUE_DATE_LOG'] = $calendarObj->calendarLog; - return $result; - } - - /** - * Calculate $sInitDate + $iDaysCount, skipping non laborable days. - * Input: Any valid strtotime function type input. - * Returns: Integer timestamp of the result. - * Warning: It will hangs if there is no possible days to count as - * "laborable". - * @param date $sInitDate - * @param double $iDuration - * @param string $sTimeUnit - * @param string $iTypeDay - * @param string $UsrUid - * @param string $ProUid - * @param string $TasUid - * @return integer timestamp of the result - * @deprecated renamed by Hugo Loza (see calculateDate new function) - */ - - function calculateDate_noCalendar( $sInitDate, $iDuration, $sTimeUnit, $iTypeDay, $UsrUid = NULL, $ProUid = NULL, $TasUid =NULL ) { - //load in class variables the config of working days, holidays etc.. - $this->prepareInformation( $UsrUid , $ProUid , $TasUid ); - $iHours = 0; $iDays = 0; - //convert the $iDuration and $sTimeUnit in hours and days, take in mind 8 hours = 1 day. and then we will have similar for 5 days = 1 weekends - if ( strtolower ( $sTimeUnit ) == 'hours' ) { - $iAux = intval(abs($iDuration)); - $iHours = $iAux % $this->hoursPerDay; - $iDays = intval( $iAux / $this->hoursPerDay ); - } - if ( strtolower ( $sTimeUnit ) == 'days' ) { - $iAux = intval(abs($iDuration * $this->hoursPerDay)); - $iHours = $iAux % 8; - $iDays = intval( $iAux / 8 ); - } - $addSign = ( $iDuration >= 0 ) ? '+' : '-'; - $iInitDate = strtotime( $sInitDate ); - if ( $iTypeDay == 1 ) { // working days - // if there are days calculate the days, - $iEndDate = $this->addDays( $iInitDate , $iDays, $addSign ); - // if there are hours calculate the hours, and probably add a day if the quantity of hours for last day > 8 hours - $iEndDate = $this->addHours( $iEndDate , $iHours, $addSign ); - } - else { // $task->getTasTypeDay() == 2 // calendar days - $iEndDate = strtotime( $addSign . $iDays . ' days ' , $iInitDate ); - $iEndDate = strtotime( $addSign . $iHours . ' hours ' , $iEndDate ); - } - return $iEndDate; - } +require_once ("classes/model/TaskPeer.php"); +require_once ("classes/model/HolidayPeer.php"); /** - * Calculate duration of the $sInitDate - $sEndDate. - * @param date $sInitDate - * @param date $sEndDate - * @param string $UsrUid - * @param string $ProUid - * @param string $TasUid - * @return int - * + * + * @package workflow.engine.classes */ - function calculateDuration( $sInitDate, $sEndDate = '', $UsrUid = NULL, $ProUid = NULL, $TasUid = NULL) { - $this->prepareInformation($UsrUid, $ProUid, $TasUid); - if ((string)$sEndDate == '') { - $sEndDate = date('Y-m-d H:i:s'); - } - if (strtotime($sInitDate) > strtotime($sEndDate)) { - $sAux = $sInitDate; - $sInitDate = $sEndDate; - $sEndDate = $sAux; - } - $aAux1 = explode(' ', $sInitDate); - $aAux2 = explode(' ', $sEndDate); - $aInitDate = explode('-', $aAux1[0]); - $aEndDate = explode('-', $aAux2[0]); - $i = 1; - $iWorkedDays = 0; - $bFinished = false; - $fHours1 = 0.0; - $fHours2 = 0.0; - if (count($aInitDate) != 3) { - $aInitDate = array(0, 0, 0); - } - if (count($aEndDate) != 3) { - $aEndDate = array(0, 0, 0); - } - if ($aInitDate !== $aEndDate) { - while (!$bFinished && ($i < 10000)) { - $sAux = date('Y-m-d', mktime(0, 0, 0, $aInitDate[1], $aInitDate[2] + $i, $aInitDate[0])); - if ($sAux != implode('-', $aEndDate)) { - if (!in_array($sAux, $this->holidays)) { - if (!in_array(date('w', mktime(0, 0, 0, $aInitDate[1], $aInitDate[2] + $i, $aInitDate[0])), $this->weekends)) { - $iWorkedDays++; +class dates +{ + private $holidays = array (); + private $weekends = array (); + private $range = array (); + private $skipEveryYear = true; + private $calendarDays = false; //by default we are using working days + private $hoursPerDay = 8; //you should change this + + + /** + * Function that calculate a final date based on $sInitDate and $iDuration + * This function also uses a Calendar component (class.calendar.php) where all the definition of + * a User, task, Process or default calendar is defined. + * base on that information is possible to setup different calendars + * and apply them to a task, process or user. Each calendar have Working Days, Business Hours and Holidays + * + * @name calculateDate + * @access public + * @author Hugo Loza + * @param date $sInitDate + * @param double $iDuration + * @param string $sTimeUnit + * @param string $iTypeDay + * @param string $UsrUid + * @param string $ProUid + * @param string $TasUid + * @return array('DUE_DATE'=>'Final calculated date formatted as Y-m-d H:i:s','DUE_DATE_SECONDS'=>'Final calculated date in seconds','OLD_DUE_DATE'=>'Using deprecate4d function','OLD_DUE_DATE_SECONDS'=>'Using deprecated function','DUE_DATE_LOG'=>'Log of all the calculations made') + * @todo test this function with negative durations (for events) + * + * + */ + function calculateDate ($sInitDate, $iDuration, $sTimeUnit, $iTypeDay, $UsrUid = NULL, $ProUid = NULL, $TasUid = NULL) + { + //$oldDate=$this->calculateDate_noCalendar( $sInitDate, $iDuration, $sTimeUnit, $iTypeDay, $UsrUid, $ProUid, $TasUid); + //Set Calendar when the object is instanced in this order/priority (Task, User, Process, Default) + G::LoadClass( 'calendar' ); + $calendarObj = new calendar( $UsrUid, $ProUid, $TasUid ); + //Get next Business Hours/Range based on : + switch (strtoupper( $sTimeUnit )) { + case 'DAYS': + $hoursToProcess = $iDuration * 8; + break; //In Hours + default: + $hoursToProcess = $iDuration; + break; //In Hours + } + $dateArray = explode( " ", $sInitDate ); + $currentDate = $dateArray[0]; + $currentTime = isset( $dateArray[1] ) ? $dateArray[1] : "00:00:00"; + + $startTime = (float) array_sum( explode( ' ', microtime() ) ); + + $calendarObj->addCalendarLog( "* Starting at: $startTime" ); + $calendarObj->addCalendarLog( ">>>>> Hours to Process: $hoursToProcess" ); + $calendarObj->addCalendarLog( ">>>>> Current Date: $currentDate" ); + $calendarObj->addCalendarLog( ">>>>> Current Time: $currentTime" ); + $array_hours = explode( ":", $currentTime ); + $seconds2 = $array_hours[2]; + $minutes2 = 0; + while ($hoursToProcess > 0) { + $validBusinessHour = $calendarObj->getNextValidBusinessHoursRange( $currentDate, $currentTime ); + //For Date/Time operations + $currentDateA = explode( "-", $validBusinessHour['DATE'] ); + $currentTimeA = explode( ":", $validBusinessHour['TIME'] ); + $hour = $currentTimeA[0]; + $minute = $currentTimeA[1]; + $second = isset( $currentTimeA[2] ) ? $currentTimeA[2] : 0; + $month = $currentDateA[1]; + $day = $currentDateA[2]; + $year = $currentDateA[0]; + $normalizedDate = date( "Y-m-d H:i:s", mktime( $hour, $minute, $second, $month, $day, $year ) ); + $normalizedDateInt = mktime( $hour, $minute, $second, $month, $day, $year ); + $normalizedDateSeconds = ($hour * 60 * 60) + ($minute * 60); + $arrayHour = explode( ".", $hoursToProcess ); + if (isset( $arrayHour[1] )) { + $minutes1 = $arrayHour[1]; + $cadm = strlen( $minutes1 ); + $minutes2 = (($minutes1 / pow( 10, $cadm )) * 60); } - } - $i++; + $possibleTime = date( "Y-m-d H:i:s", mktime( $hour + $hoursToProcess, $minute + $minutes2, $second + $seconds2, $month, $day, $year ) ); + $possibleTimeInt = mktime( $hour + $hoursToProcess, $minute + $minutes2, $second + $seconds2, $month, $day, $year ); + $offsetPermitedMinutes = "0"; + $calendarBusinessEndA = explode( ":", $validBusinessHour['BUSINESS_HOURS']['CALENDAR_BUSINESS_END'] ); + $calendarBusinessEndNormalized = date( "Y-m-d H:i:s", mktime( $calendarBusinessEndA[0], $calendarBusinessEndA[1] + $offsetPermitedMinutes, 0, $month, $day, $year ) ); + $calendarBusinessEndInt = mktime( $calendarBusinessEndA[0], $calendarBusinessEndA[1] + $offsetPermitedMinutes, 0, $month, $day, $year ); + $calendarBusinessEndSeconds = ($calendarBusinessEndA[0] * 60 * 60) + ($calendarBusinessEndA[1] * 60); + $calendarObj->addCalendarLog( "Possible time: $possibleTime" ); + $calendarObj->addCalendarLog( "Current Start Date/Time: $normalizedDate" ); + $calendarObj->addCalendarLog( "Calendar Business End: $calendarBusinessEndNormalized" ); + if ($possibleTimeInt > $calendarBusinessEndInt) { + $currentDateTimeB = explode( " ", $calendarBusinessEndNormalized ); + $currentDate = $currentDateTimeB[0]; + $currentTime = $currentDateTimeB[1]; + $diff = abs( $normalizedDateSeconds - $calendarBusinessEndSeconds ); + $diffHours = $diff / 3600; + $hoursToProcess = $hoursToProcess - $diffHours; + } else { + $currentDateTimeA = explode( " ", $possibleTime ); + $currentDate = $currentDateTimeA[0]; + $currentTime = $currentDateTimeA[1]; + $hoursToProcess = 0; + } + $calendarObj->addCalendarLog( "** Hours to Process: $hoursToProcess" ); } - else { - $bFinished = true; - } - } - if (isset($aAux1[1])) { - $aAux1[1] = explode(':', $aAux1[1]); - $fHours1 = 24 - ($aAux1[1][0] + ($aAux1[1][1] / 60) + ($aAux1[1][2] / 3600)); - } - if (isset($aAux2[1])) { - $aAux2[1] = explode(':', $aAux2[1]); - $fHours2 = $aAux2[1][0] + ($aAux2[1][1] / 60) + ($aAux2[1][2] / 3600); - } - $fDuration = ($iWorkedDays * 24) + $fHours1 + $fHours2; - } - else { - $fDuration = (strtotime($sEndDate) - strtotime($sInitDate)) / 3600; - } - return $fDuration; - } - - /** - * Configuration functions - * @param string $UsrUid - * @param string $ProUid - * @param string $TasUid - * @return void - */ - function prepareInformation( $UsrUid = NULL , $ProUid = NULL , $TasUid =NULL ) - { - // setup calendarDays according the task - if (isset($TasUid)) - { - $task = TaskPeer::retrieveByPK( $TasUid ); - if (!is_null($task)) { - $this->calendarDays = ($task->getTasTypeDay()==2); - } + $calendarObj->addCalendarLog( "+++++++++++ Calculated Due Date $currentDate $currentTime" ); + $result['DUE_DATE'] = $currentDate . " " . $currentTime; + $result['DUE_DATE_SECONDS'] = strtotime( $currentDate . " " . $currentTime ); + //$result['OLD_DUE_DATE'] = date("Y-m-d H:i:s",$oldDate); + //$result['OLD_DUE_DATE_SECONDS']= $oldDate; + + + $endTime = (float) array_sum( explode( ' ', microtime() ) ); + $calendarObj->addCalendarLog( "* Ending at: $endTime" ); + $calcTime = round( $endTime - $startTime, 3 ); + $calendarObj->addCalendarLog( "** Processing time: " . sprintf( "%.4f", ($endTime - $startTime) ) . " seconds" ); + $result['DUE_DATE_LOG'] = $calendarObj->calendarLog; + return $result; } - //get an array with all holidays. - $aoHolidays=HolidayPeer::doSelect(new Criteria()); - $holidays=array(); - foreach($aoHolidays as $holiday) - $holidays[] = strtotime($holiday->getHldDate()); - - // by default the weekdays are from monday to friday - $this->weekends = array(0,6); - $this->holidays = $holidays; - return ; - } - - /** - * Set to repeat for every year all dates defined in $this->holiday - * @param $bSkipEveryYear - * @return void - */ - function setSkipEveryYear( $bSkipEveryYear ) - { - $this->skipEveryYear = $bSkipEveryYear===true; - } - - /** - * Add a single date to holidays - * @param data $sDate - * @return void - */ - function addHoliday( $sDate ) - { - if ($date=strtotime( $sDate )) $this->holidays[]=self::truncateTime($date); - else throw new Exception("Invalid date: $sDate."); - } - - /** - * Set all the holidays - * @param date/array $aDate must be an array of (strtotime type) dates - * @return void - */ - function setHolidays( $aDates ) - { - foreach($aDates as $sDate) $this->holidays = $aDates; - } - - /** - * Set all the weekends - * @param array/integers $aWeekends must be an array of integers [1,7] - * 1=Sunday - * 7=Saturday - * @return void - */ - function setWeekends( $aWeekends ) - { - $this->weekends = $aWeekends; - } - - /** - * Add one day of week to the weekends list - * @param $iDayNumber must be an array of integers [1,7] - * 1=Sunday - * 7=Saturday - * @return void - */ - function skipDayOfWeek( $iDayNumber ) - { - if ($iDayNumber<1 || $iDayNumber>7) throw new Exception("The day of week must be a number from 1 to 7."); - $this->weekends[]=$iDayNumber; - } - - /** - * Add a range of non working dates - * @param date $sDateA must be a (strtotime type) dates - * @param date $sDateB must be a (strtotime type) dates - * @return void - */ - function addNonWorkingRange( $sDateA , $sDateB ) - { - if ($date=strtotime( $sDateA )) $iDateA=self::truncateTime($date); - else throw new Exception("Invalid date: $sDateA."); - if ($date=strtotime( $sDateB )) $iDateB=self::truncateTime($date); - else throw new Exception("Invalid date: $sDateB."); - if ($iDateA>$iDateB) { $s=$iDateA;$iDateA=$iDateB;$iDateB=$s; }; - $this->range[]=array( $iDateA , $iDateB ); - } - - /** - * PRIVATE UTILITARY FUNCTIONS - * Add days to the date - * @param date $iInitDate - * @param int $iDaysCount - * @param string $addSign - * @return date $iEndDate - */ - private function addDays( $iInitDate , $iDaysCount, $addSign = '+' ) - { - $iEndDate = $iInitDate; - $aList = $this->holidays; - for( $r=1; $r <= $iDaysCount ; $r++) { - $iEndDate = strtotime( $addSign . "1 day", $iEndDate ); - $dayOfWeek = idate('w',$iEndDate); //now sunday=0 - if ( array_search( $dayOfWeek, $this->weekends )!== false ) $r--; //continue loop, but we are adding one more day. - } - return $iEndDate; - } - - /** - * Add hours to the date - * @param date $iInitDate - * @param int $iHoursCount - * @param string $addSign - * @return $iEndDate - */ - - private function addHours( $sInitDate , $iHoursCount, $addSign = '+' ) - { - $iEndDate = strtotime( $addSign . $iHoursCount ." hours", $sInitDate ); - return $iEndDate; - } - - /** - * Compare if the date is in range - * @param $iDate = valid timestamp - * @return true if it is within any of the ranges defined. - */ - private function inRange( $iDate ) - { - $aRange = $this->range; - $iYear = idate( 'Y', $iDate ); - foreach($aRange as $key => $rang) - { - if ($this->skipEveryYear) - { - $deltaYears = idate( 'Y', $rang[1] ) - idate( 'Y', $rang[0] ); - $rang[0]=self::changeYear( $rang[0] , $iYear ); - $rang[1]=self::changeYear( $rang[1] , $iYear + $deltaYears ); - } - if (($iDate>=$rang[0]) && ($iDate<=$rang[1])) return true; - } - return false; - } - - /** - * Truncate a date - * @param $iDate = valid timestamp - * @return date - */ - private function truncateTime( $iDate ) - { - return mktime(0,0,0,idate('m',$iDate),idate('d',$iDate),idate('Y',$iDate)); - } - - /** - * Get time - * @param timestamp $iDate - * @return date - */ - private function getTime( $iDate ) - { - return array(idate('H',$iDate),idate('m',$iDate),idate('s',$iDate)); - } - - /** - * Set time - * @param timestamp $iDate - * @param timestamp $aTime - * @return date - */ - private function setTime( $iDate , $aTime ) - { - return mktime($aTime[0],$aTime[1],$aTime[2],idate('m',$iDate),idate('d',$iDate),idate('Y',$iDate)); - } - -/** - * Returns an array with all the dates of $this->skip['List'] with its - * year changed to $iYear. - * Warning: Don't know what to do if change a 29-02-2004 to 29-02-2005 - * the last one doesn't exist. - * @param List $iYear - * @return array - */ - private function listForYear( $iYear ) - { - $aList = $this->holidays; - foreach($aList as $k => $v) - { - $aList[$k] = self::changeYear( $v , $iYear ); - } - return $aList; - } + /** + * Calculate $sInitDate + $iDaysCount, skipping non laborable days. + * Input: Any valid strtotime function type input. + * Returns: Integer timestamp of the result. + * Warning: It will hangs if there is no possible days to count as + * "laborable". + * + * @param date $sInitDate + * @param double $iDuration + * @param string $sTimeUnit + * @param string $iTypeDay + * @param string $UsrUid + * @param string $ProUid + * @param string $TasUid + * @return integer timestamp of the result + * @deprecated renamed by Hugo Loza (see calculateDate new function) + */ -/** - * Returns an array with all the dates of $this->skip['List'] with its - * year changed to $iYear. - * Warning: Don't know what to do if change a 29-02-2004 to 29-02-2005 - * the last one doesn't exist. - * @param array $iYear - * @param date $iDate - * @return array - */ - private function changeYear( $iDate , $iYear ) - { - if ($delta = ( $iYear - idate('Y',$iDate) ) ) + function calculateDate_noCalendar ($sInitDate, $iDuration, $sTimeUnit, $iTypeDay, $UsrUid = NULL, $ProUid = NULL, $TasUid = NULL) { - $iDate = strtotime( "$delta year" , $iDate ); + //load in class variables the config of working days, holidays etc.. + $this->prepareInformation( $UsrUid, $ProUid, $TasUid ); + $iHours = 0; + $iDays = 0; + //convert the $iDuration and $sTimeUnit in hours and days, take in mind 8 hours = 1 day. and then we will have similar for 5 days = 1 weekends + if (strtolower( $sTimeUnit ) == 'hours') { + $iAux = intval( abs( $iDuration ) ); + $iHours = $iAux % $this->hoursPerDay; + $iDays = intval( $iAux / $this->hoursPerDay ); + } + if (strtolower( $sTimeUnit ) == 'days') { + $iAux = intval( abs( $iDuration * $this->hoursPerDay ) ); + $iHours = $iAux % 8; + $iDays = intval( $iAux / 8 ); + } + $addSign = ($iDuration >= 0) ? '+' : '-'; + $iInitDate = strtotime( $sInitDate ); + if ($iTypeDay == 1) { // working days + // if there are days calculate the days, + $iEndDate = $this->addDays( $iInitDate, $iDays, $addSign ); + // if there are hours calculate the hours, and probably add a day if the quantity of hours for last day > 8 hours + $iEndDate = $this->addHours( $iEndDate, $iHours, $addSign ); + } else { // $task->getTasTypeDay() == 2 // calendar days + $iEndDate = strtotime( $addSign . $iDays . ' days ', $iInitDate ); + $iEndDate = strtotime( $addSign . $iHours . ' hours ', $iEndDate ); + } + return $iEndDate; + } + + /** + * Calculate duration of the $sInitDate - $sEndDate. + * + * @param date $sInitDate + * @param date $sEndDate + * @param string $UsrUid + * @param string $ProUid + * @param string $TasUid + * @return int + * + */ + function calculateDuration ($sInitDate, $sEndDate = '', $UsrUid = NULL, $ProUid = NULL, $TasUid = NULL) + { + $this->prepareInformation( $UsrUid, $ProUid, $TasUid ); + if ((string) $sEndDate == '') { + $sEndDate = date( 'Y-m-d H:i:s' ); + } + if (strtotime( $sInitDate ) > strtotime( $sEndDate )) { + $sAux = $sInitDate; + $sInitDate = $sEndDate; + $sEndDate = $sAux; + } + $aAux1 = explode( ' ', $sInitDate ); + $aAux2 = explode( ' ', $sEndDate ); + $aInitDate = explode( '-', $aAux1[0] ); + $aEndDate = explode( '-', $aAux2[0] ); + $i = 1; + $iWorkedDays = 0; + $bFinished = false; + $fHours1 = 0.0; + $fHours2 = 0.0; + if (count( $aInitDate ) != 3) { + $aInitDate = array (0,0,0 + ); + } + if (count( $aEndDate ) != 3) { + $aEndDate = array (0,0,0 + ); + } + if ($aInitDate !== $aEndDate) { + while (! $bFinished && ($i < 10000)) { + $sAux = date( 'Y-m-d', mktime( 0, 0, 0, $aInitDate[1], $aInitDate[2] + $i, $aInitDate[0] ) ); + if ($sAux != implode( '-', $aEndDate )) { + if (! in_array( $sAux, $this->holidays )) { + if (! in_array( date( 'w', mktime( 0, 0, 0, $aInitDate[1], $aInitDate[2] + $i, $aInitDate[0] ) ), $this->weekends )) { + $iWorkedDays ++; + } + } + $i ++; + } else { + $bFinished = true; + } + } + if (isset( $aAux1[1] )) { + $aAux1[1] = explode( ':', $aAux1[1] ); + $fHours1 = 24 - ($aAux1[1][0] + ($aAux1[1][1] / 60) + ($aAux1[1][2] / 3600)); + } + if (isset( $aAux2[1] )) { + $aAux2[1] = explode( ':', $aAux2[1] ); + $fHours2 = $aAux2[1][0] + ($aAux2[1][1] / 60) + ($aAux2[1][2] / 3600); + } + $fDuration = ($iWorkedDays * 24) + $fHours1 + $fHours2; + } else { + $fDuration = (strtotime( $sEndDate ) - strtotime( $sInitDate )) / 3600; + } + return $fDuration; + } + + /** + * Configuration functions + * + * @param string $UsrUid + * @param string $ProUid + * @param string $TasUid + * @return void + */ + function prepareInformation ($UsrUid = NULL, $ProUid = NULL, $TasUid = NULL) + { + // setup calendarDays according the task + if (isset( $TasUid )) { + $task = TaskPeer::retrieveByPK( $TasUid ); + if (! is_null( $task )) { + $this->calendarDays = ($task->getTasTypeDay() == 2); + } + } + + //get an array with all holidays. + $aoHolidays = HolidayPeer::doSelect( new Criteria() ); + $holidays = array (); + foreach ($aoHolidays as $holiday) + $holidays[] = strtotime( $holiday->getHldDate() ); + + // by default the weekdays are from monday to friday + $this->weekends = array (0,6 + ); + $this->holidays = $holidays; + return; + } + + /** + * Set to repeat for every year all dates defined in $this->holiday + * + * @param $bSkipEveryYear + * @return void + */ + function setSkipEveryYear ($bSkipEveryYear) + { + $this->skipEveryYear = $bSkipEveryYear === true; + } + + /** + * Add a single date to holidays + * + * @param data $sDate + * @return void + */ + function addHoliday ($sDate) + { + if ($date = strtotime( $sDate )) + $this->holidays[] = self::truncateTime( $date ); + else + throw new Exception( "Invalid date: $sDate." ); + } + + /** + * Set all the holidays + * + * @param date/array $aDate must be an array of (strtotime type) dates + * @return void + */ + function setHolidays ($aDates) + { + foreach ($aDates as $sDate) + $this->holidays = $aDates; + } + + /** + * Set all the weekends + * + * @param array/integers $aWeekends must be an array of integers [1,7] + * 1=Sunday + * 7=Saturday + * @return void + */ + function setWeekends ($aWeekends) + { + $this->weekends = $aWeekends; + } + + /** + * Add one day of week to the weekends list + * + * @param $iDayNumber must be an array of integers [1,7] + * 1=Sunday + * 7=Saturday + * @return void + */ + function skipDayOfWeek ($iDayNumber) + { + if ($iDayNumber < 1 || $iDayNumber > 7) + throw new Exception( "The day of week must be a number from 1 to 7." ); + $this->weekends[] = $iDayNumber; + } + + /** + * Add a range of non working dates + * + * @param date $sDateA must be a (strtotime type) dates + * @param date $sDateB must be a (strtotime type) dates + * @return void + */ + function addNonWorkingRange ($sDateA, $sDateB) + { + if ($date = strtotime( $sDateA )) + $iDateA = self::truncateTime( $date ); + else + throw new Exception( "Invalid date: $sDateA." ); + if ($date = strtotime( $sDateB )) + $iDateB = self::truncateTime( $date ); + else + throw new Exception( "Invalid date: $sDateB." ); + if ($iDateA > $iDateB) { + $s = $iDateA; + $iDateA = $iDateB; + $iDateB = $s; + } + ; + $this->range[] = array ($iDateA,$iDateB + ); + } + + /** + * PRIVATE UTILITARY FUNCTIONS + * Add days to the date + * + * @param date $iInitDate + * @param int $iDaysCount + * @param string $addSign + * @return date $iEndDate + */ + private function addDays ($iInitDate, $iDaysCount, $addSign = '+') + { + $iEndDate = $iInitDate; + $aList = $this->holidays; + for ($r = 1; $r <= $iDaysCount; $r ++) { + $iEndDate = strtotime( $addSign . "1 day", $iEndDate ); + $dayOfWeek = idate( 'w', $iEndDate ); //now sunday=0 + if (array_search( $dayOfWeek, $this->weekends ) !== false) + $r --; //continue loop, but we are adding one more day. + } + return $iEndDate; + } + + /** + * Add hours to the date + * + * @param date $iInitDate + * @param int $iHoursCount + * @param string $addSign + * @return $iEndDate + */ + + private function addHours ($sInitDate, $iHoursCount, $addSign = '+') + { + $iEndDate = strtotime( $addSign . $iHoursCount . " hours", $sInitDate ); + return $iEndDate; + } + + /** + * Compare if the date is in range + * + * @param $iDate = valid timestamp + * @return true if it is within any of the ranges defined. + */ + private function inRange ($iDate) + { + $aRange = $this->range; + $iYear = idate( 'Y', $iDate ); + foreach ($aRange as $key => $rang) { + if ($this->skipEveryYear) { + $deltaYears = idate( 'Y', $rang[1] ) - idate( 'Y', $rang[0] ); + $rang[0] = self::changeYear( $rang[0], $iYear ); + $rang[1] = self::changeYear( $rang[1], $iYear + $deltaYears ); + } + if (($iDate >= $rang[0]) && ($iDate <= $rang[1])) + return true; + } + return false; + } + + /** + * Truncate a date + * + * @param $iDate = valid timestamp + * @return date + */ + private function truncateTime ($iDate) + { + return mktime( 0, 0, 0, idate( 'm', $iDate ), idate( 'd', $iDate ), idate( 'Y', $iDate ) ); + } + + /** + * Get time + * + * @param timestamp $iDate + * @return date + */ + private function getTime ($iDate) + { + return array (idate( 'H', $iDate ),idate( 'm', $iDate ),idate( 's', $iDate ) + ); + } + + /** + * Set time + * + * @param timestamp $iDate + * @param timestamp $aTime + * @return date + */ + private function setTime ($iDate, $aTime) + { + return mktime( $aTime[0], $aTime[1], $aTime[2], idate( 'm', $iDate ), idate( 'd', $iDate ), idate( 'Y', $iDate ) ); + } + + /** + * Returns an array with all the dates of $this->skip['List'] with its + * year changed to $iYear. + * Warning: Don't know what to do if change a 29-02-2004 to 29-02-2005 + * the last one doesn't exist. + * + * @param List $iYear + * @return array + */ + private function listForYear ($iYear) + { + $aList = $this->holidays; + foreach ($aList as $k => $v) { + $aList[$k] = self::changeYear( $v, $iYear ); + } + return $aList; + } + + /** + * Returns an array with all the dates of $this->skip['List'] with its + * year changed to $iYear. + * Warning: Don't know what to do if change a 29-02-2004 to 29-02-2005 + * the last one doesn't exist. + * + * @param array $iYear + * @param date $iDate + * @return array + */ + private function changeYear ($iDate, $iYear) + { + if ($delta = ($iYear - idate( 'Y', $iDate ))) { + $iDate = strtotime( "$delta year", $iDate ); + } + return $iDate; } - return $iDate; - } } ?> \ No newline at end of file