function testGetDTEnd()
    {
        $ics = <<<ICS
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Apple Inc.//iCal 4.0.4//EN
CALSCALE:GREGORIAN
BEGIN:VEVENT
TRANSP:OPAQUE
DTEND;TZID=America/New_York:20070925T170000
UID:uuid
DTSTAMP:19700101T000000Z
LOCATION:
DESCRIPTION:
STATUS:CONFIRMED
SEQUENCE:18
SUMMARY:Stuff
DTSTART;TZID=America/New_York:20070925T160000
CREATED:20071004T144642Z
RRULE:FREQ=MONTHLY;INTERVAL=1;UNTIL=20071030T035959Z;BYDAY=5TU
END:VEVENT
END:VCALENDAR
ICS;
        $vObject = Reader::read($ics);
        $it = new RecurrenceIterator($vObject, (string) $vObject->VEVENT->UID);
        while ($it->valid()) {
            $it->next();
        }
        // If we got here, it means we were successful. The bug that was in teh
        // system before would fail on the 5th tuesday of the month, if the 5th
        // tuesday did not exist.
    }
    function testMinusOne()
    {
        $ics = <<<ICS
BEGIN:VCALENDAR
BEGIN:VEVENT
DTSTAMP:20120314T203127Z
UID:foo
SUMMARY:foo
RRULE:FREQ=YEARLY;UNTIL=20120314
DTSTART;VALUE=DATE:20120315
DTEND;VALUE=DATE:20120316
SEQUENCE:1
END:VEVENT
END:VCALENDAR
ICS;
        $vObject = Reader::read($ics);
        $it = new RecurrenceIterator($vObject, (string) $vObject->VEVENT->UID);
        $this->assertTrue($it->valid());
    }
 /**
  * Parses the input data and returns a correct VFREEBUSY object, wrapped in
  * a VCALENDAR.
  *
  * @return Component
  */
 public function getResult()
 {
     $busyTimes = array();
     foreach ($this->objects as $object) {
         foreach ($object->getBaseComponents() as $component) {
             switch ($component->name) {
                 case 'VEVENT':
                     $FBTYPE = 'BUSY';
                     if (isset($component->TRANSP) && strtoupper($component->TRANSP) === 'TRANSPARENT') {
                         break;
                     }
                     if (isset($component->STATUS)) {
                         $status = strtoupper($component->STATUS);
                         if ($status === 'CANCELLED') {
                             break;
                         }
                         if ($status === 'TENTATIVE') {
                             $FBTYPE = 'BUSY-TENTATIVE';
                         }
                     }
                     $times = array();
                     if ($component->RRULE) {
                         $iterator = new RecurrenceIterator($object, (string) $component->uid);
                         if ($this->start) {
                             $iterator->fastForward($this->start);
                         }
                         $maxRecurrences = 200;
                         while ($iterator->valid() && --$maxRecurrences) {
                             $startTime = $iterator->getDTStart();
                             if ($this->end && $startTime > $this->end) {
                                 break;
                             }
                             $times[] = array($iterator->getDTStart(), $iterator->getDTEnd());
                             $iterator->next();
                         }
                     } else {
                         $startTime = $component->DTSTART->getDateTime();
                         if ($this->end && $startTime > $this->end) {
                             break;
                         }
                         $endTime = null;
                         if (isset($component->DTEND)) {
                             $endTime = $component->DTEND->getDateTime();
                         } elseif (isset($component->DURATION)) {
                             $duration = DateTimeParser::parseDuration((string) $component->DURATION);
                             $endTime = clone $startTime;
                             $endTime->add($duration);
                         } elseif ($component->DTSTART->getDateType() === Property\DateTime::DATE) {
                             $endTime = clone $startTime;
                             $endTime->modify('+1 day');
                         } else {
                             // The event had no duration (0 seconds)
                             break;
                         }
                         $times[] = array($startTime, $endTime);
                     }
                     foreach ($times as $time) {
                         if ($this->end && $time[0] > $this->end) {
                             break;
                         }
                         if ($this->start && $time[1] < $this->start) {
                             break;
                         }
                         $busyTimes[] = array($time[0], $time[1], $FBTYPE);
                     }
                     break;
                 case 'VFREEBUSY':
                     foreach ($component->FREEBUSY as $freebusy) {
                         $fbType = isset($freebusy['FBTYPE']) ? strtoupper($freebusy['FBTYPE']) : 'BUSY';
                         // Skipping intervals marked as 'free'
                         if ($fbType === 'FREE') {
                             continue;
                         }
                         $values = explode(',', $freebusy);
                         foreach ($values as $value) {
                             list($startTime, $endTime) = explode('/', $value);
                             $startTime = DateTimeParser::parseDateTime($startTime);
                             if (substr($endTime, 0, 1) === 'P' || substr($endTime, 0, 2) === '-P') {
                                 $duration = DateTimeParser::parseDuration($endTime);
                                 $endTime = clone $startTime;
                                 $endTime->add($duration);
                             } else {
                                 $endTime = DateTimeParser::parseDateTime($endTime);
                             }
                             if ($this->start && $this->start > $endTime) {
                                 continue;
                             }
                             if ($this->end && $this->end < $startTime) {
                                 continue;
                             }
                             $busyTimes[] = array($startTime, $endTime, $fbType);
                         }
                     }
                     break;
             }
         }
     }
     if ($this->baseObject) {
         $calendar = $this->baseObject;
     } else {
         $calendar = Component::create('VCALENDAR');
         $calendar->version = '2.0';
         $calendar->prodid = '-//Sabre//Sabre VObject ' . Version::VERSION . '//EN';
         $calendar->calscale = 'GREGORIAN';
     }
     $vfreebusy = Component::create('VFREEBUSY');
     $calendar->add($vfreebusy);
     if ($this->start) {
         $dtstart = Property::create('DTSTART');
         $dtstart->setDateTime($this->start, Property\DateTime::UTC);
         $vfreebusy->add($dtstart);
     }
     if ($this->end) {
         $dtend = Property::create('DTEND');
         $dtend->setDateTime($this->end, Property\DateTime::UTC);
         $vfreebusy->add($dtend);
     }
     $dtstamp = Property::create('DTSTAMP');
     $dtstamp->setDateTime(new \DateTime('now'), Property\DateTime::UTC);
     $vfreebusy->add($dtstamp);
     foreach ($busyTimes as $busyTime) {
         $busyTime[0]->setTimeZone(new \DateTimeZone('UTC'));
         $busyTime[1]->setTimeZone(new \DateTimeZone('UTC'));
         $prop = Property::create('FREEBUSY', $busyTime[0]->format('Ymd\\THis\\Z') . '/' . $busyTime[1]->format('Ymd\\THis\\Z'));
         $prop['FBTYPE'] = $busyTime[2];
         $vfreebusy->add($prop);
     }
     return $calendar;
 }