Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>This is basically an adaptation of @Loopo's algorithm.</p> <p>First, it'd be nice to be able to compare times using <code>&gt;</code> and <code>&lt;</code>, so first we convert all times (day of week + hour/minute/second) to UNIX time offsets:</p> <pre><code>// Code is messy and probably depends on how you structure things internally. function timeOffset($dayOfWeek, $time) { // TODO Use standard libraries for this. $daysOfWeek = array('Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'); $splitTime = explode(':', $time); $offset = (((int)array_search($dayOfWeek, $daysOfWeek) * 24 + (int)$time[0]) * 60 + (int)$time[1]) * 60 + (int)$time[2]; return $offset; } $rateTable = array( 'Monday' =&gt; array( '00:00:00' =&gt; 1.5, '08:00:00' =&gt; 1, '17:00:00' =&gt; 1.5, ), 'Tuesday' =&gt; array( '00:00:00' =&gt; 1.5, '08:00:00' =&gt; 1, '17:00:00' =&gt; 1.5, ) ); $clockedTimes = array( array('Monday', '15:00:00', '21:00:00') ); $rateTableConverted = array(); foreach($rateTable as $dayOfWeek =&gt; $times) { foreach($times as $time =&gt; $multiplier) { $offset = timeOffset($dayOfWeek, $time); $rateTableConverted[$offset] = $multiplier; } } ksort($rateTableConverted); $clockedTimesConverted = array(); foreach($clockedTimes as $clock) { $convertedClock = array( 'start' =&gt; timeOffset($clock[0], $clock[1]), 'end' =&gt; timeOffset($clock[0], $clock[2]), ); $clockedTimesConverted[] = $convertedClock; } </code></pre> <p>Ideally, this would have already been done (e.g. you store these converted offsets in the database instead of the original <code>xx:yy:zz D</code> strings).</p> <p>Now the splitter (with a helper due to the lack of closures):</p> <pre><code>class BetweenValues { public $start, $end; public function __construct($start, $end) { $this-&gt;start = $start; $this-&gt;end = $end; } public function isValueBetween($value) { return $this-&gt;start &lt;= $value &amp;&amp; $value &lt;= $this-&gt;end; } } class TimeRangeSplitter { private $rateTable; public function __construct($rateTable) { $this-&gt;rateTable = $rateTable; } private function getIntersectingTimes($times, $start, $end) { ksort($times); $betweenCalculator = new BetweenValues($start, $end); $intersecting = array_filter($times, array($betweenCalculator, 'isValueBetween')); /* If possible, get the time before this one so we can use its multiplier later. */ if(key($intersecting) &gt; 0 &amp;&amp; current($intersecting) != $start) { array_unshift($intersecting, $times[key($intersecting) - 1]); } return array_values($intersecting); } public function getSplitTimes($start, $end) { $splits = array(); $intersecting = $this-&gt;getIntersectingTimes(array_keys($this-&gt;rateTable), $start, $end); $curTime = $start; $curMultiplier = 0; foreach($intersecting as $sectionStartTime) { $splits[] = $this-&gt;getSplit($curTime, $sectionStartTime, $curMultiplier, $curTime); $curMultiplier = $this-&gt;rateTable[$sectionStartTime]; } $splits[] = $this-&gt;getSplit($curTime, $end, $curMultiplier, $curTime); return array_filter($splits); } private function getSplit($time, $split, $multiplier, &amp;$newTime) { $ret = NULL; if($time &lt; $split) { $ret = array( 'start' =&gt; $time, 'end' =&gt; $split, 'multiplier' =&gt; $multiplier, ); $newTime = $split; } return $ret; } } </code></pre> <p>And using the class:</p> <pre><code>$splitClockedTimes = array(); $splitter = new TimeRangeSplitter($rateTableConverted); foreach($clockedTimesConverted as $clocked) { $splitClockedTimes[] = $splitter-&gt;getSplitTimes($clocked['start'], $clocked['end']); } var_dump($splitClockedTimes); </code></pre> <p>Hope this helps.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload