3

新しい PHP DateTime クラスを利用するカレンダー アプリケーションがあります。定期的なイベントを処理する方法はありますが、ハックっぽいので、もっと良いアイデアがあるかどうかを確認したかったのです。

  1. 2009 年 11 月 16 日 (2009 年 11 月 16 日) に始まる定期的なイベントがあります。
  2. 3日おきに発生します
  3. イベントは無期限に繰り返されます

ユーザーが 3100 年 12 月のカレンダーを見たとします。このイベントは、通常どおり 3 日ごとに繰り返されるはずです。問題は、その月の日数をどのように計算するかです。

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

これは私が基本的に行う方法ですが、もっと簡単なものが欠けていることはわかっています。

  1. $daysDiff として格納されている月の開始日 (3100 年 12 月 1 日) とイベントの開始日 (2009 年 11 月 16 日) の間の日数の差を計算します。
  2. モジュラスを差し引くと、次のように開始から 3 日の係数が得られます: $daysDiff - ($daysDiff % 3)
  3. 議論のために、3100 年 11 月 29 日が日付として与えられるとしましょう。
  4. 次に、すべての日付が 3100 年 12 月以内になるまで、その日付に 3 日を繰り返し追加します。

私の主な問題は、ステップ 1 にあります。PHP の DateInterval::date_diff 関数は、日数の差を計算しません。それは私に何年も何ヶ月も何日も与えるでしょう。2009 年 11 月 16 日 + (1090 年 * 365.25 日) + (9 か月 * 30.5 日) + 15 日

9999 年のように実際に遠い未来に行くと、この見積もりは 1 か月ずれることがあり、必要な場所に到達するには 3 日間の間隔を大幅に差し引く必要があります。

4

2 に答える 2

9

これは、DatePeriod を Iterator として使用して適切に行うことができ、表示する開始日でフィルター処理されます。

<?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" );
}
?>
于 2009-11-18T11:30:53.570 に答える
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.

明らかに、ユーザーが任意の月を選択できるように交換する変数がいくつかありますが、それが基本的なアルゴリズムである必要があります。また、DateTimes が正しい日付であることを確認してください。ただし、時刻は 00:00:00 に設定されています。そうしないと、最初の while ループが解決されません。これは、選択した日付がイベントの開始日より後の日付であることを確認していることも前提としています。

于 2009-11-17T21:01:05.430 に答える