2009-11-17 38 views
3

我有一个日历应用程序,它利用了较新的PHP DateTime类。我有处理经常性项目的方式,但它似乎砍十岁上下,我想看看,如果你们有更好的想法:PHP 5.3重复事件的日期时间

  1. 我有开始11/16/2009重复发生的事件(11月16日, 2009)
  2. 将每3天
  3. 发生的事件将再次发生无限期

比方说,用户查看日历十二月,3100 - 此事件应显示有每3天重复正常人一样。问题是 - 我如何计算那个月的那些日子?

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

这就是我基本上做到这一点,但我知道我失去了一些东西简单:

  1. 我计算差值在天月初之间看(12月1日,3100)和事件开始日期(2009年11月16日)存储为$ daysDiff
  2. 我减去模数,以便从开始时获得3天的系数,如下所示:$ daysDiff - ($ daysDiff%3)
  3. 为了争论起见,让我说31月11日,31日为我的日期。
  4. 我再用3天添加到那个日期,直到我有内十二月3100所有日期

我的主要问题来自步骤1. PHP DateInterval :: date_diff功能不计算天数的差异。它会给我几年,几个月和几天。 11/16/2009 +(1090年* 365.25天)+(9个月* 30.5天)+ 15天

当你去真正的时候像9999年这样的未来,这个估计可能会关闭一个月,然后我必须减去很多3天的时间间隔才能获得我需要的地方。

回答

3

您可以将您的日期格式化为unix时间戳,然后使用模块化部门在所选月份中查找第一个实例,然后以3天为单位进行步骤。因此,对于你的例子:

$startDate = new DateTime(20091116); 
$startTimestamp = $startDate->format('u'); 
$recursEvery = 259200; // 60*60*24*3 = seconds in 3 days 

// find the first occurrence in the selected month (September) 
$calendarDate = new DateTime(31000901); // init to Sept 1, 3100 
while (0 != (($calendarDate->format('u') - $startTimestamp) % $recursEvery)) { 
    $calendarDate->modify('+1 day'); 
} 

$effectiveDates = array(); 
while ($calendarDate->format('m') == 9) { 
    $effectiveDates[] = clone $calendarDate; 
    $calendarDate->modify('+3 day'); 
} 

//$effectiveDates is an array of every date the event occurs in September, 3100. 

很显然,你有几个变量,以换出,使用户可以选择任何一个月份,但应该是基本的算法。此外,请确保您的日期时间是正确的日期,但时间设置为00:00:00,否则第一个while循环将永远不会解析。这也假设你已经确保所选日期晚于事件的开始日期。

+0

...当然,Unix时间戳的事情不会对全年工作3100除非你用64位运行。 – keithjgrant

+0

嗨基思 - 我喜欢你用这种方式思考的方式,但那不幸对我来说也是一个限制(在32位上)。这似乎是直接“数学”与这些日期不能完成,检查我的“fudging”方式做到这一点 – John

+0

它确实如果您在时间戳前面放置一个'@',如下所示:new DateTime('@' 。$时间戳); 哇,没意识到这是09年的最后一次活动....对不起。 – Adam

9

这可以很好地使用DatePeriod作为一个Iterator filterd完成,然后开始日期要显示:

<?php 
class DateFilterIterator extends FilterIterator { 
    private $starttime; 
    public function __construct(Traversable $inner, DateTime $start) { 
     parent::__construct(new IteratorIterator($inner)); 
     $this->starttime = $start->getTimestamp(); 
    } 
    public function accept() { 
     return ($this->starttime < $this->current()->getTimestamp()); 
    } 
} 

$db = new DateTime('2009-11-16'); 
$de = new DateTime('2020-12-31 23:59:59'); 
$di = DateInterval::createFromDateString('+3 days'); 
$df = new DateFilterIterator(
    new DatePeriod($db, $di, $de), 
    new DateTime('2009-12-01')); 

foreach ($df as $dt) 
{ 
    echo $dt->format("l Y-m-d H:i:s\n"); 
} 
?>