PHP 5.3 DateTime 用于重复事件

发布于 2024-08-11 03:17:49 字数 858 浏览 9 评论 0原文

我有一个日历应用程序,它使用较新的 PHP DateTime 类。我有一种处理重复事件的方法,但它看起来很黑客,我想看看你们是否有更好的想法:

  1. 我有一个从 2009 年 11 月 16 日(2009 年 11 月 16 日)开始的重复事件,
  2. 它将发生在每个3 天
  3. 该事件将无限期地重复

假设用户查看 12 月 3100 年的日历 - 该事件应该像平常一样显示每 3 天重复一次。问题是 - 我如何计算该月的那些天数?

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

这就是我基本上做的它,但我知道我错过了一些更简单的东西:

  1. 我计算了所查看的月份开始日期(3100年12月1日)和事件开始日期(2009年11月16日)之间的天数差异,存储为$daysDiff
  2. 我减去模数,这样我就得到了从一开始就 3 天的因子,如下所示: $daysDiff - ($daysDiff % 3)
  3. 为了便于论证,我们可以假设 3100 年 11 月 29 日为日期。
  4. 然后,我反复向该日期添加 3 天,直到获得 3100 年 12 月内的所有日期。

我的主要问题来自步骤 1。PHP DateInterval::date_diff 函数不计算天数差异。它会给我几年、几个月、几天。然后我必须捏造数字才能得到 3100 年 12 月左右的估计日期。 11/16/2009 + (1090 年 * 365.25 天) + (9 个月 * 30.5 天) + 15 天

当你真正进入遥远的未来,比如 9999 年,这个估计可能会偏差一个月,那么我必须减去很多 3 天的间隔才能到达我需要的地方。

I have a calendar application which utilizes the newer PHP DateTime classes. I have a way that I handle recurring events, but it seems hack-ish and I wanted to see if you guys have better ideas:

  1. I have a recurring event that starts 11/16/2009 (Nov 16, 2009)
  2. It will occur every 3 days
  3. The event will recur indefinitely

Let's say the user looks at the calendar for Dec, 3100 - this event should show there repeating every 3 days like normal. The question is - how do I calculate those days in that month?

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

This is how I basically do it, but I know I'm missing something easier:

  1. I calculate the difference in days between the start of the month being looked at (Dec 1, 3100) and the event start date (Nov 16, 2009) stored as $daysDiff
  2. I subtract the modulus, so that I get a factor of 3 days from the start like this: $daysDiff - ($daysDiff % 3)
  3. For the sake of argument lets say that gives me Nov 29, 3100 as a date.
  4. I then add 3 days to that date repeatedly until I have all the dates within Dec 3100

My main problem comes with step 1. The PHP DateInterval::date_diff function does not calculate differences in days. It will give me years, months, and days. I then have to fudge the numbers to get an estimate date around Dec, 3100.
11/16/2009 + (1090 years * 365.25 days) + (9 months * 30.5 days) + 15 days

When you go REAL far into the future like the year 9999, this estimation can be off by a month, then I have to subtract a lot of 3 day intervals to get where I need.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

想你的星星会说话 2024-08-18 03:17:49

使用 DatePeriod 作为迭代器,然后过滤到您想要显示的开始日期,可以很好地完成此操作:

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

This can be done nicely using a DatePeriod as an Iterator and then filterd to the start date you want to display:

<?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" );
}
?>
绝不服输 2024-08-18 03:17:49

您可以将日期格式化为 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.

显然,您需要交换一些变量,以便用户可以选择任何月份,但这应该是基本算法。另外,请确保您的 DateTimes 是正确的日期,但时间设置为 00:00:00,否则第一个 while 循环将永远无法解析。这还假设您已确保所选日期晚于事件的开始日期。

You could format your date as a unix timestamp then use modular division to find the first instance in the selected month, then step in increments of 3 days from there. So for your example:

$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.

Obviously, you've got a few variables to swap out so the user can select any month, but that should be the basic algorithm. Also, ensure your DateTimes are the correct date, but with the time set as 00:00:00, or else the first while loop will never resolve. This also assumes you've ensured the selected date is later than the beginning date of the event.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文