Php 重复每月和每年的活动-如何确保准确性?

Php 重复每月和每年的活动-如何确保准确性?,php,calendar,strtotime,recurring-events,Php,Calendar,Strtotime,Recurring Events,我目前允许在我的日历应用程序上每天或每周重复事件(使用fullCalendar) 我的视图有一个复选框,可以激活两个下拉列表:一个用于重复间隔(每天、每周),另一个用于频率(一次、两次等) 这可以很好地基于数据库中的单个记录条目显示多个每日或每周事件 问题是每月和每年。因为这些将有可变的秒数,因为 03/01/2011 00:00:00 --> 04/01/2011 00:00:00 ===> 2674800 seconds 04/01/2011 00:00:00 --> 05

我目前允许在我的日历应用程序上每天或每周重复事件(使用fullCalendar)

我的视图有一个复选框,可以激活两个下拉列表:一个用于重复间隔(每天、每周),另一个用于频率(一次、两次等)

这可以很好地基于数据库中的单个记录条目显示多个每日或每周事件

问题是每月和每年。因为这些将有可变的秒数,因为

03/01/2011 00:00:00 --> 04/01/2011 00:00:00 ===> 2674800 seconds
04/01/2011 00:00:00 --> 05/01/2011 00:00:00 ===> 2592000 seconds
and so on for monthly and yearly differences
那么我如何解决这个问题呢?是否有任何功能或
strotime
命令可帮助准确指示每月应在第4天重复,或每年应在第4天重复


我使用的是PHP5.2.14。

strotime可以做一些令人惊奇的事情,比如“下个月的今天”和“下个星期的2011-05-09”。你可以用这些来做一些基本的日期调整。但是,在日历类型的情况下,它无法正确处理此问题。如果你说“2011-01-30下个月”,它不会给你2月30日,而是给你3月1日/2日(取决于闰年)


您可能需要将日期分解为单独的y/m/d/h/m/s组件,调整重复组件,然后使用mktime()重新组装,但即使这样,也会将错误日期修复为等效的正常日期。换句话说,您必须对“调整后”日期进行验证,以确保它们对您的目的有效。

似乎可以与PHP中的
DateTime
类配合使用

$dt = new DateTime('3rd Jan 2011');
echo $dt->format('r') . PHP_EOL;

$dt->modify('+1 year');
echo $dt->format('r') . PHP_EOL;
编辑:您必须特别考虑如何处理每月复发,因为对于29、30、31,它们可能不会在本月出现。以下是意外输出的示例:

$dt = new DateTime('29 Jan 2011');
echo $dt->format('r') . PHP_EOL;

$dt->modify('+1 month');
echo $dt->format('r') . PHP_EOL;
如果要确保准确性,不应使用秒数。如果DST在时间范围内发生变化,您将遇到问题,并且您的计算将不准确。此外,由于月份的天数不尽相同,您不能继续使用秒数进行计数


我建议使用PHP DateTime类和/或
strotime
。后者用简单的英语理解日期:
strotime(“下个月的第二个星期一”)
返回6月13日的时间戳。

感谢所有回答-我通过来自

这样做的目的是解决在
29天、30天、31天以及
2月28日反复发生的每月事件的问题

我喜欢这个功能,因为它解决了我的日历应用程序POV的问题

如果用户请求从1月31日开始的每月定期事件
normal
strotime
将在2月和没有31天的任何其他月份表现不稳定

正如我在上面的评论中指出的,谷歌日历通过跳过没有这样的日期的月份来解决这个问题,这有点奇怪

我想这是一个偏好的问题,但对我来说,将重复事件放在一个月的最后一天更有意义——因此在
1月31日
的例子中,重复事件将发生在
2月28日
3月31日
4月30日
等等

我把这个函数放在一个循环中,循环重复用户请求的次数,它工作得很好。它在年度活动中也能很好地发挥作用,因为我只是将
12
作为月数来传递。

这是一个有趣的点——如果你把一个活动放在谷歌日历上,比如2011年1月31日,并要求它每月重复3次,它会跳过2月和4月。
$dt = new DateTime('3rd Jan 2011');
echo $dt->format('r') . PHP_EOL;

$dt->modify('+1 year');
echo $dt->format('r') . PHP_EOL;
$dt = new DateTime('29 Jan 2011');
echo $dt->format('r') . PHP_EOL;

$dt->modify('+1 month');
echo $dt->format('r') . PHP_EOL;
$evt_interval_options = array( //this will be $row->interval in the model
    '86400' => 'Daily',   
    '604800' => 'Weekly';
function get_x_months_to_the_future( $base_time = null, $months = 1 )
{
    if (is_null($base_time))
        $base_time = time();

    $x_months_to_the_future    = strtotime( "+" . $months . " months", $base_time );

    $month_before              = (int) date( "m", $base_time ) + 12 * (int) date( "Y", $base_time );
    $month_after               = (int) date( "m", $x_months_to_the_future ) + 12 * (int) date( "Y", $x_months_to_the_future );

    if ($month_after > $months + $month_before)
        $x_months_to_the_future = strtotime( date("Ym01His", $x_months_to_the_future) . " -1 day" );

    return $x_months_to_the_future;
}