3

私はいくつかの会場のグループの予約可用性システムに取り組んでおり、特定の月の数日間の時間ブロックの可用性を生成するのに苦労しています。これはPHPのサーバー側で発生していますが、概念自体は言語に依存しません。JSなどでこれを行うことができます。

与えられたvenue_id、month、およびyear(たとえば、6/2012)を指定すると、その会場でその範囲で発生するすべてのイベントのリストが、UNIXタイムスタンプstartおよびとして表されendます。このデータはデータベースから取得されます。最小の長さ(会場ごとに異なる)の連続した時間ブロックが毎日存在する場合は、それを確立する必要があります。

たとえば、6/1に午後2時から午後7時の間にイベントがあります。最短時間は5時間なので、午前9時から午後2時まで、午後7時から午後12時までブロックが開いています。これは、6月の毎日2日、3日などに続きます。何も起こらない日もあれば、1〜3回のイベントもあります。

私が思いついた解決策はうまくいきましたが、データを生成するのに時間がかかりすぎました。基本的に、私はその月の毎日をループし、その日の15分ごとにタイムスタンプの配列を作成します。次に、その日からのイベントの期間を15分ループし、「取得された」タイムスロットをfalseとしてマークします。残りの部分には、空き時間と所要時間のタイムスタンプを含む配列があります。

//one day's array after processing through loops (not real timestamps)
array(
  12345678=>12345678,   // <--- avail
  12345878=>12345878,
  12346078=>12346078,
  12346278=>false,      // <--- not avail
  12346478=>false,
  12346678=>false,
  12346878=>false,
  12347078=>12347078,   // <--- avail
  12347278=>12347278
)

次に、この配列をループして連続する時間ブロックを見つけ、それらが十分に長いかどうかを確認し(各会場には最小値があります)、そうであれば、開始と終了の説明テキストを確立する必要があります(つまり、午前9時から午後2時)。 。わあ!このすべてのループが完了するまでに、ユーザーは退屈になり、子犬のビデオを見るためにYouTubeに迷い込んでいます。30日ほど調べるのに何年もかかります。

この問題を解決するためのより速い方法はありますか?問題を要約すると、d日の時間範囲t1t2が与えられた場合、最小時間ブロックmよりも長いdに残っている残り時間をどのように決定できますか。

このデータは、ユーザーが暦月間を移動するときに、AJAXを介してオンデマンドで収集されます。結果はページの読み込みごとにキャッシュされるため、ユーザーが2回目に7月に移動した場合、最初に生成されたデータが再利用されます。

役立つその他の詳細があれば、私に知らせてください。


編集

リクエストごとに、データベース構造(またはここで関連する部分)

*events*
id        (bigint)
title     (varchar)

*event_times*
id        (bigint)
event_id  (bigint)
venue_id  (bigint)
start     (bigint)
end       (bigint)

*venues*
id        (bigint)
name      (varchar)
min_block (int)
min_start (varchar)
max_start (varchar)

イベントは常に15から始まります-:00、:15、:30、:45

いくつかの実際のタイムスタンプのデータダンプ:http://pastebin.com/k1PRkj44

4

2 に答える 2

1

これはあなたを正しい方向に導くはずです(私は願っています)。ある期間(たとえば1か月)に含まれるデータベースレコードを繰り返し処理します。

そのセットから、予約間の「ギャップ」を見つけて、配列を埋めます(日付をキーとして)。

$days = array();

$stmt = $db->prepare('SELECT
    DATE(FROM_UNIXTIME(start)) AS sdate,
    GROUP_CONCAT(HOUR(FROM_UNIXTIME(start)),",", MINUTE(FROM_UNIXTIME(start)) ORDER BY start ASC SEPARATOR ",") AS from_hours,
    GROUP_CONCAT(HOUR(FROM_UNIXTIME(end)), ",", MINUTE(FROM_UNIXTIME(end)) ORDER BY start ASC SEPARATOR ",") AS to_hours
    FROM event_time
    WHERE start >= ? AND end < ? AND start < end
    GROUP BY sdate
    ORDER BY sdate');

$stmt->execute(array($from, $to));
foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
    // from and to are formatted as: [hh,mm,hh,mm,hh,mm,...]
    $from = explode(',', $row['from_hours']);
    $to = explode(',', $row['to_hours']);

    // skew the two arrays:
    // - add 00:00 in the front of $to
    // - add 23:59 at the back of $from
    array_unshift($to, 0, 0);
    array_push($from, 23, 59);

    for ($i = 0, $n = count($from); $i != $n; $i += 2) {
        // create time values
        $start = new DateTime("{$to[$i]}:{$to[$i+1]}");
        $end = new DateTime("{$from[$i]}:{$from[$i+1]}");

        // calculate difference
        $diff = $start->diff($end);
        // difference must be positive and at least 5 hours apart (depending on venue)
        if (!$diff->invert && $diff->h >= 5) {
            $days[$row['sdate']][] = array($start->format('H:i'), $end->format('H:i'));
        }
    }
}

最後に、$daysには次のものが含まれます。

[2012-06-30] => Array
    (
        [0] => Array
            (
                [0] => 00:00
                [1] => 05:30
            )

        [1] => Array
            (
                [0] => 11:30
                [1] => 23:59
            )

    )

計算を行うために変更する必要のある変数がいくつかあります。

  1. 最小時間(例:早朝から)
  2. 最大時間(例:夜遅くまで)
  3. 最小予約時間(会場によって異なります)

また、結果の配列にないキーは1日中利用できるため、$daysクエリを実行している期間内のすべての日でループを開始する前に、配列を準備する必要があります。

それがあなたを助けたかどうか私に知らせてください:)

于 2012-06-07T08:13:37.940 に答える
0

利用可能な時間のリストを作成します。各エントリには、開始時刻と終了時刻があります。時間の最初から最後まで実行される1つのエントリから開始します。データベースから使用時間を読み取ります。既存のエントリの最初または最後にある場合は、適切に短くします。真ん中にある場合は、1つを短くして、新しいものを追加する必要があります(同時にカバーするために、真ん中にギャップがあります)。これにより、何時間にもわたるイベントで15分のスロットを見る必要がなくなります。また、スロットが15分ではなく5分になっても機能します。

DBを読むと、1つの時系列リストにすべての空き期間があります。サイズでソートされた別のリストにそれらを配置することもできます。

リンクリストは、ほとんど順番にアクセスするため、最も論理的な選択かもしれません。すばやく追加および削除できます。ある種の配列は遅くなるはずですが、最近の配列は非常に高速であり、バイナリ検索も可能になります。非常に頻繁に使用する場合、ある種のツリーベース(ソートされたシーケンシャルアクセス用)の辞書またはマップは、両方の長所を提供します(高速な追加と削除、およびランダムアクセス)。この場合、はある種の配列を使用すると思います。

これは少し手間がかかりますが、実際の速度が得られる可能性があります。

于 2012-06-11T20:00:26.187 に答える