3

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

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

$evt_interval_options = array( //this will be $row->interval in the model
    '86400' => 'Daily',   
    '604800' => 'Weekly'; 

$evt_frequency_options = array(  //this will be //$i in the model
    '1' => '2',    
    '2' => '3',    

<?php echo form_checkbox('evt_repeat', 'FALSE', FALSE, 'class="repeat_checkbox"'); 
      echo form_dropdown('evt_interval', $evt_interval_options');
      echo form_dropdown('evt_frequency', $evt_frequency_options'); ?>

这最终会到达我的模型,它会运行一个循环来检查事件是否应该重复——如果是这样,它将考虑间隔 ( $row->interval) 和频率 ( $i)。

$cal_data[] = array(
    'start' => strtotime($row->date_1 . ' ' . $row->time_1) + ($i ? ($row->interval * $i) : 0),
);

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

问题在于每月和每年。由于这些将具有可变的秒数,因为

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

那么我该如何解决这个问题呢?是否有任何功能或strtotime命令可以帮助准确地指示每月应在 eg 上重复4th或每年应在 eg 上重复July 4th

我正在使用 PHP 5.2.14。

4

4 回答 4

5

感谢所有回答 - 我通过strtotime()的PHP.net 手册中的@akniep解决了这个函数的问题。

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

这样做是为了解决在几天内重复发生的每月事件29, 30, 31以及Feb 28.

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

Jan 31如果用户请求从正常开始的每月重复事件,strtotime则在 2 月和任何其他没有 31 天的月份期间将出现异常行为。

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

我想这是一个偏好问题,但对我来说,将重复事件放置在每月的最后一天更有意义 - 所以在Jan 31示例中,重复事件将发生Feb 28 Mar 31 Apr 30等等。

我将此函数放在一个循环中,该循环迭代用户请求的多次重复,并且它运行良好。它在年度活动中也很有效,因为我只是通过12月份数。

于 2011-05-10T02:54:05.740 回答
3

似乎与DateTimePHP 中的类一起工作正常

$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;
于 2011-05-09T20:31:26.747 回答
2
$evt_interval_options = array( //this will be $row->interval in the model
    '86400' => 'Daily',   
    '604800' => 'Weekly';

如果要确保准确性,则不应使用秒数。如果时间范围内 DST 发生变化,您就会遇到问题,并且您的计算将不准确。此外,由于月份的天数并不相同,因此您不能仅使用秒数继续计数。

我建议使用 PHP DateTime 类和/或strtotime. 后者以简单的英语理解日期:strtotime('seconds monday of next month');返回 6 月 13 日的时间戳。

于 2011-05-09T20:39:08.633 回答
1

strtotime 可以做一些令人惊奇的事情,例如“下个月的今天”和“下周的 2011-05-09”。您可以使用它们来进行一些基本的日期调整。但是,它在日历类型的情况下无法正确处理。如果您说“下个月 2011 年 1 月 30 日”,它不会给您 2 月 30 日,而是给您 3 月 1 日/2 日(取决于闰年)。

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

于 2011-05-09T20:28:19.280 回答