谷歌日历API算法:寻找给定日期的空闲时间段

3

我正在尝试利用Google Calendar(和Google Calendar API)进行简单的预定。我使用PHP,MySQL和google-api-php-client。我正在寻找一种算法或伪代码来查找空闲时间段。

我的日历上有繁忙时间的事件,例如营业时间以及当前约会。通过两个函数(Events:list和Freebusy:query),我能够检索到事件的开始和结束时间。以下是今天的事件列表示例,起始时间为2016-02-19T01:00:00-07:00,终止时间为2016-02-19T23:00:00-07:00(所有内容均为当天)。

营业时间从12:00am至11:00am
开始:"2016-02-19T00:00:00-07:00"
结束:"2016-02-19T11:00:00-07:00"

1:30pm至2:30pm的约会
开始:"2016-02-19T13:30:00-07:00"
结束:"2016-02-19T14:30:00-07:00"

5:00pm至7:00pm的约会
开始:"2016-02-19T17:00:00-07:00"
结束:"2016-02-19T19:00:00-07:00"

9:00pm至11:00pm的约会
开始:"2016-02-19T21:00:00-07:00"
结束:"2016-02-19T23:00:00-07:00"

基于此示例事件集,我的空闲时间段是:上午11:00至下午1:30,下午2:30至下午5:00,晚上7:00至9:00和晚上11:00至凌晨12:00。

  1. 我如何以编程方式找到这组时间?

理想情况下,我希望用一个API调用获取给定日的完整事件列表,并解释/处理该列表,而不是进行许多带有特定起始和终止时间的调用,这将为我提供所需信息,但效率非常低。

  1. 在找到该集之后,我如何以30分钟的间隔显示结果,即可用的约会开始时间为:

11:00、11:30、12:00、12:30、1:00、2:30、3:00、3:30、4:00、4:30、9:00、9:30、10:00、10:30、11:00、11:30

我很难理解如何处理日期/时间数据集。

这是一张Google日历的图片。所涉及的日期为2016年2月19日。
谢谢您的帮助。任何由此讨论产生的资源都将被发布供参考。
2个回答

4
我会将日期转换为Unix时间戳,并计算开始日期和结束日期之间的差异。这是我完成你问题的第一部分的方法:
$events = array(
    array(
        'start' => '2016-02-19T00:00:00-07:00',
        'end' => '2016-02-19T11:00:00-07:00'
    ),
    array(
        'start' => '2016-02-19T13:30:00-07:00',
        'end' => '2016-02-19T14:30:00-07:00'
    ),
    array(
        'start' => '2016-02-19T17:00:00-07:00',
        'end' => '2016-02-19T19:00:00-07:00'
    ),
    array(
        'start' => '2016-02-19T21:00:00-07:00',
        'end' => '2016-02-19T23:00:00-07:00'
    )
);

$free_time_slots = array();
$count = count($events)-1;
$i = 0;
foreach($events as $event) {
    if ($i < $count) {
        $free_time = strtotime($events[$i+1]['start']) - strtotime($event['end']);
        $free_time_slots[] = array(
            'start' => date("F j, Y, g:i a", strtotime($event['end'])),
            'end' => date("F j, Y, g:i a", strtotime($events[$i+1]['start'])),
            'minutes' => $free_time / 60
        );
        $i++;
    }
}  
echo '<pre>';
print_r($free_time_slots);

这将导致如下结果:
Array
(
    [0] => Array
        (
            [start] => February 19, 2016, 11:00 am
            [end] => February 19, 2016, 1:30 pm
            [minutes] => 150
        )

    [1] => Array
        (
            [start] => February 19, 2016, 2:30 pm
            [end] => February 19, 2016, 5:00 pm
            [minutes] => 150
        )

    [2] => Array
        (
            [start] => February 19, 2016, 7:00 pm
            [end] => February 19, 2016, 9:00 pm
            [minutes] => 120
        )

)

谢谢!@nickthompson - evolution9

3
这应该可以完成工作。您可以循环遍历要搜索的时间范围内的每个约会时间段。在该循环中,您可以检查您当前的每个约会是否存在冲突。此代码将在每次迭代后回显空闲约会时间,但您可能希望将它们推入数组中,以便在任何需要使用它们的地方使用。
// Set timezone = UTC for consistency
date_default_timezone_set("UTC");

// Range to search for open times in.
$start_time = strtotime("2016-02-19T00:00:00-07:00");
$end_time = strtotime("2016-02-19T23:59:59-07:00");

// Test data
$events = array(
    "event_1" => array(
        "start" => "2016-02-19T00:00:00-07:00",
        "end" => "2016-02-19T11:00:00-07:00"
    ),
    "event_2" => array(
        "start" => "2016-02-19T13:30:00-07:00",
        "end" => "2016-02-19T14:30:00-07:00"
    ),
    "event_3" => array(
        "start" => "2016-02-19T17:00:00-07:00",
        "end" => "2016-02-19T19:00:00-07:00"
    ),
    "event_4" => array(
        "start" => "2016-02-19T21:00:00-07:00",
        "end" => "2016-02-19T23:00:00-07:00"
    ),
);

// Kick off first appt time at beginning of the day.
$appt_start_time = $start_time;

// Loop through each appt slot in the search range.
while ($appt_start_time < $end_time) {
    // Add 29:59 to the appt start time so we know where the appt will end.
    $appt_end_time = ($appt_start_time + 1799);

    // For each appt slot, loop through the current appts to see if it falls
    // in a slot that is already taken.
    $slot_available = true;
    foreach ($events as $event => $times) {
        $this_start = strtotime($times['start']);
        $this_end = strtotime($times['end']);

        // If the appt start time or appt end time falls on a current appt, slot is taken.
        if (($appt_start_time >= $this_start && $appt_start_time < $this_end) ||
            ($appt_end_time >= $this_start && $appt_end_time < $this_end)) {
            $slot_available = false;
            break; // No need to continue if it's taken.
        }
    }

    // If we made it through all appts and the slot is still available, it's an open slot.
    if ($slot_available) {
        $date = new DateTime();
        $date->setTimestamp($appt_start_time);
        $date->setTimezone(new DateTimeZone("America/Denver"));
        echo "Open appt at: ". $date->format("Y-m-d h:i:s-e") ."<br />";
    }

    // + 30 minutes
    $appt_start_time += (60 * 30);
}

这将导致:
Open appt at: 2016-02-19 11:00:00-America/Denver
Open appt at: 2016-02-19 11:30:00-America/Denver
Open appt at: 2016-02-19 12:00:00-America/Denver
Open appt at: 2016-02-19 12:30:00-America/Denver
Open appt at: 2016-02-19 01:00:00-America/Denver
Open appt at: 2016-02-19 02:30:00-America/Denver
Open appt at: 2016-02-19 03:00:00-America/Denver
Open appt at: 2016-02-19 03:30:00-America/Denver
Open appt at: 2016-02-19 04:00:00-America/Denver
Open appt at: 2016-02-19 04:30:00-America/Denver
Open appt at: 2016-02-19 07:00:00-America/Denver
Open appt at: 2016-02-19 07:30:00-America/Denver
Open appt at: 2016-02-19 08:00:00-America/Denver
Open appt at: 2016-02-19 08:30:00-America/Denver
Open appt at: 2016-02-19 11:00:00-America/Denver
Open appt at: 2016-02-19 11:30:00-America/Denver

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接