计算给定日期范围内的时间块

时间:2009-09-09 02:32:49

标签: php datetime

我正在尝试从给定的日期范围计算时间块。这是我的尝试:

<?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;
  }

}

我无法在:: calculate()中找到我应该做的循环。

测试用例:

<?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版本是5.2.6所以不能使用像:: diff()这样的DateTime东西。

修改

因此范围就是

================================

阻止

#######

因此,范围中的块是

=====###=====###====....=====###
     ^ ^                     ^ ^
     | |                     | |
     |  - end of block 1     |  - end of block N
      - start of block 1      - start of block N

1 个答案:

答案 0 :(得分:0)

好的,这似乎工作正常:

  /**
   * 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 = clone $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");

      // It's not last day of range, so it's full day
      if ($rangeStart->format("Ymd") !== $this->rangeEnd->format("Ymd"))
      {
        $rangeEnd->setDate($blockEnd->format('Y'), $blockEnd->format('m'), $blockEnd->format('d'));
        $rangeEnd->setTime($blockEnd->format('G'), $blockEnd->format('i'), $blockEnd->format('s'));

        if ($rangeEnd > $this->rangeEnd)
        {
          $rangeEnd->setTime(0, 0, 0);
        }
      }

      // It's first day of range, so it's probably partial day
      if ($rangeStart->format("Ymd") === $this->rangeStart->format("Ymd"))
      {
        if ($rangeStart < $blockStart)
        {
          $rangeStart->setTime($blockStart->format('G'), $blockStart->format('i'), $blockStart->format('s'));
        }
      }

      // Add to results
      if ($rangeStart < $rangeEnd)
      {
        $result[] = array(clone $rangeStart, clone $rangeEnd);
      }

      // Full day after first iteration
      $rangeStart->setTime(0, 0, 0);

      $rangeStart->modify("+1 day");
    }
    while ($blockEnd <= $this->rangeEnd);

    return $result;
  }

修改: 不,这个