Повторение ежемесячных и ежегодных событий - как обеспечить точность? - PullRequest
3 голосов
/ 10 мая 2011

В настоящее время я разрешаю ежедневные или еженедельные повторения событий в приложении календаря (с использованием 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, которая может помочь точно указать, что месячные должны повторяться, например, 4th или годовой должен повторяться July 4th?

Я использую PHP 5.2.14.

Ответы [ 4 ]

5 голосов
/ 10 мая 2011

Спасибо всем, кто ответил - я решил проблему с этой функцией с помощью @ akniep из руководства PHP.net по strtotime () .

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, будет вести себя неуверенно в течение февраля и любого другого месяца, в котором нет 31 дня.

Как я указал в комментарии выше, GoogleКалендарь решает эту проблему несколько странно, пропуская месяцы, в которых такой даты нет.

Я полагаю, это вопрос предпочтений, но для меня имеет смысл предложить разместить повторяющееся событие в последний день месяца.- поэтому в примере Jan 31 повторяющиеся события будут происходить Feb 28 Mar 31 Apr 30 и т. д.

Я поместил эту функцию в цикл, который повторяет столько же повторенийпользователь запрашивает, и он работает отлично.Это также хорошо работает в ежегодных событиях, для этого я просто передаю 12 как количество месяцев.

3 голосов
/ 10 мая 2011

Кажется, отлично работает с классом DateTime в PHP

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

$dt->modify('+1 year');
echo $dt->format('r') . PHP_EOL;

edit: Вы должны будете уделить особое внимание тому, как вы справляетесь с ежемесячным повторением, поскольку для 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;
2 голосов
/ 10 мая 2011
$evt_interval_options = array( //this will be $row->interval in the model
    '86400' => 'Daily',   
    '604800' => 'Weekly';

Вы не должны использовать количество секунд, если хотите обеспечить точность.Если во временных рамках произойдет изменение летнего времени, у вас будут проблемы, и ваши расчеты будут неточными.Также, поскольку месяцы не имеют одинаковое количество дней, вы не можете просто продолжать считать, используя секунды.

Я бы посоветовал использовать класс PHP DateTime и / или strtotime.Последний понимает даты простым языком: strtotime('seconds monday of next month'); возвращает отметку времени за 13 июня.

1 голос
/ 10 мая 2011

strtotime может делать удивительные вещи, такие как «сегодня в следующем месяце» и «2011-05-09 на следующей неделе».Вы можете использовать их, чтобы сделать некоторые основные корректировки даты.Тем не менее, он не будет обрабатывать это правильно в ситуации типа календаря.Если вы скажете «2011-01-30 в следующем месяце», это не даст вам 30 февраля, это даст вам 1/2 марта (в зависимости от високосных годов).

Возможно, вам придется деконструировать вашдаты в отдельные компоненты y / m / d / h / m / s, отрегулируйте повторяющийся компонент, а затем снова соберите с помощью mktime (), но даже это исправит неправильные даты в эквивалентные нормальные.Другими словами, вам нужно будет выполнить проверку с датами «после корректировки», чтобы убедиться, что они действительны для ваших целей.

...