I'm trying to calculate time blocks from given date range. Here's my attempt:
<?php
class timeRangeCalculator
{
/**
* Start time of block
*
* @var DateTime
*/
private $blockStart;
/**
* Block duration in seconds
*
* @var int
*/
private $blockDuration;
/**
* Start of range
*
* @var DateTime
*/
private $rangeStart;
/**
* End of range
*
* @var DateTime
*/
private $rangeEnd;
/**
*
*/
public function __construct()
{
if (!class_exists('DateTime'))
{
throw new Exception('Built-in DateTime class not found');
}
}
/**
* Set whole time range
*
* @param DateTime $start
* @param DateTime $end
*/
public function setRange(DateTime $start, DateTime $end)
{
if ($end < $start)
{
throw new Exception('End cannot be before start');
}
if ($start === $end)
{
throw new Exception('Start and end cannot be same');
}
$this->rangeStart = $start;
$this->rangeEnd = $end;
return true;
}
/**
* Set time block. Ignore year and month.
*
* @param DateTime $start
* @param int $duration duration in seconds
*/
public function setBlock(DateTime $start, $duration)
{
if (!is_int($duration))
{
throw new Exception('Duration is not integer');
}
if ($duration > 86400)
{
throw new Exception('Duration is over one day');
}
$this->blockStart = $start;
$this->blockDuration = $duration;
return true;
}
/**
* Calculate time blocks from range
*
* @return array Returns array of blocks
*/
public function calculate()
{
$result = array();
$rangeStart = $this->rangeStart;
$blockStart = $this->blockStart;
$blockDuration = $this->blockDuration;
do
{
// Reset end range
$rangeEnd = $this->rangeEnd;
// Set block's starting date to range's start date
$blockStart->setDate($rangeStart->format('Y'), $rangeStart->format('m'), $rangeStart->format('d'));
$blockEnd = clone $blockStart;
$blockEnd->modify("+$blockDuration seconds");
$rangeEnd->setDate($blockEnd->format('Y'), $blockEnd->format('m'), $blockEnd->format('d'));
if ($rangeStart < $blockStart)
{
$rangeStart->setTime($blockStart->format('G'), $blockStart->format('i'), $blockStart->format('s'));
}
if ($rangeEnd > $blockEnd)
{
$rangeEnd->setTime($blockEnd->format('G'), $blockEnd->format('i'), $blockEnd->format('s'));
}
if ($rangeStart < $rangeEnd)
{
$result[] = array($rangeStart, $rangeEnd);
}
// Full day after first iteration
$rangeStart->setTime(0, 0, 0);
$rangeStart->modify("+1 day");
}
while ($blockEnd <= $this->rangeEnd);
return $result;
}
}
I can't quite get what kind of loop I should do in ::calculate().
Test case:
<?php
$block_start = new DateTime("2000-01-01 22:00:00");
$block_range = 60 * 60 * 8;
$ranges = array(
array(new DateTime("2009-01-01 00:00:00"), new DateTime("2009-01-02 00:00:00")),
array(new DateTime("2009-01-01 00:00:00"), new DateTime("2009-01-07 00:00:00"))
);
$trc = new timeRangeCalculator();
$trc->setBlock($block_start, $block_range);
foreach ($ranges as $idx => $rangeInfo)
{
list($start, $end) = $rangeInfo;
echo "Range " . $start->format("j.n.Y H:i:s") . " - " . $end->format("j.n.Y H:i:s") . "<br />";
$trc->setRange($start, $end);
$result = $trc->calculate();
if(is_array($result) && !empty($result))
{
echo "Has block 22-06: <br />";
foreach ($result as $block)
{
list($bs, $be) = $block;
echo "* " . $bs->format("j.n.Y H:i:s") . " - " . $be->format("j.n.Y H:i:s") . "<br />";
}
}
echo "<br />";
}
PHP version is 5.2.6 so some DateTime stuff like ::diff() cannot be used.
Edit:
So range is for example
================================
Block is
#######
So blocks from ranges is for example
=====###=====###====....=====###
^ ^ ^ ^
| | | |
| - end of block 1 | - end of block N
- start of block 1 - start of block N