/** * Helper method to correctly interpret an all-day date value */ public static function convert_datetime($prop, $as_array = false) { if (empty($prop)) { return $as_array ? array() : null; } else { if ($prop instanceof VObject\Property\MultiDateTime) { $dt = array(); $dateonly = $prop->getDateType() & VObject\Property\DateTime::DATE; foreach ($prop->getDateTimes() as $item) { $item->_dateonly = $dateonly; $dt[] = $item; } } else { if ($prop instanceof VObject\Property\ICalendar\DateTime) { //$dt = $prop->getDateTime(); $dt = new DateTime($prop->getValue()); } else { if ($prop instanceof VObject\Property && ($prop['VALUE'] == 'DATE' || $prop['VALUE'] == 'DATE-TIME')) { $dt = new DateTime($prop->getValue()); } else { if ($prop instanceof VObject\Property && $prop['VALUE'] == 'PERIOD') { $dt = array(); foreach (explode(',', $prop->getValue()) as $val) { try { list($start, $end) = explode('/', $val); list($type, $item) = VObject\Property\DateTime::parseData($start, $prop); $item->_dateonly = $type & VObject\Property\DateTime::DATE; $dt[] = $item; } catch (Exception $e) { // ignore single date parse errors } } } else { if ($prop instanceof DateTime) { $dt = $prop; } } } } } } // force return value to array if requested if ($as_array && !is_array($dt)) { $dt = empty($dt) ? array() : array($dt); } return $dt; }
/** * Parses the internal data structure to figure out what the current date * and time is. * * The returned array contains two elements: * 1. A 'DateType' constant (as defined on this class), or null. * 2. A DateTime object (or null) * * @param string|null $propertyValue The string to parse (yymmdd or * ymmddThhmmss, etc..) * @param \Sabre\VObject\Property|null $property The instance of the * property we're parsing. * @return array */ public static function parseData($propertyValue, VObject\Property $property = null) { if (is_null($propertyValue)) { return array(null, null); } $date = '(?P<year>[1-2][0-9]{3})(?P<month>[0-1][0-9])(?P<date>[0-3][0-9])'; $time = '(?P<hour>[0-2][0-9])(?P<minute>[0-5][0-9])(?P<second>[0-5][0-9])'; $regex = "/^{$date}(T{$time}(?P<isutc>Z)?)?\$/"; if (!preg_match($regex, $propertyValue, $matches)) { throw new \InvalidArgumentException($propertyValue . ' is not a valid \\DateTime or Date string'); } if (!isset($matches['hour'])) { // Date-only return array(self::DATE, new \DateTime($matches['year'] . '-' . $matches['month'] . '-' . $matches['date'] . ' 00:00:00', new \DateTimeZone('UTC'))); } $dateStr = $matches['year'] . '-' . $matches['month'] . '-' . $matches['date'] . ' ' . $matches['hour'] . ':' . $matches['minute'] . ':' . $matches['second']; if (isset($matches['isutc'])) { $dt = new \DateTime($dateStr, new \DateTimeZone('UTC')); $dt->setTimeZone(new \DateTimeZone('UTC')); return array(self::UTC, $dt); } // Finding the timezone. $tzid = $property['TZID']; if (!$tzid) { // This was a floating time string. This implies we use the // timezone from date_default_timezone_set / date.timezone ini // setting. return array(self::LOCAL, new \DateTime($dateStr)); } // To look up the timezone, we must first find the VCALENDAR component. $root = $property; while ($root->parent) { $root = $root->parent; } if ($root->name === 'VCALENDAR') { $tz = VObject\TimeZoneUtil::getTimeZone((string) $tzid, $root); } else { $tz = VObject\TimeZoneUtil::getTimeZone((string) $tzid); } $dt = new \DateTime($dateStr, $tz); $dt->setTimeZone($tz); return array(self::LOCALTZ, $dt); }
/** * Create a Sabre\VObject\Property instance from a PHP DateTime object * * @param string Property name * @param object DateTime */ public function datetime_prop($name, $dt, $utc = false, $dateonly = null) { $is_utc = $utc || ($tz = $dt->getTimezone()) && in_array($tz->getName(), array('UTC', 'GMT', 'Z')); $is_dateonly = $dateonly === null ? (bool) $dt->_dateonly : (bool) $dateonly; $vdt = new VObject\Property\DateTime($name); $vdt->setDateTime($dt, $is_dateonly ? VObject\Property\DateTime::DATE : ($is_utc ? VObject\Property\DateTime::UTC : VObject\Property\DateTime::LOCALTZ)); // register timezone for VTIMEZONE block if (!$is_utc && !$dateonly && $tz && ($tzname = $tz->getName())) { $ts = $dt->format('U'); if (is_array($this->vtimezones[$tzname])) { $this->vtimezones[$tzname][0] = min($this->vtimezones[$tzname][0], $ts); $this->vtimezones[$tzname][1] = max($this->vtimezones[$tzname][1], $ts); } else { $this->vtimezones[$tzname] = array($ts, $ts); } } return $vdt; }
/** * @depends testValues */ function testComplexExclusions() { $ev = new Component('VEVENT'); $ev->UID = 'bla'; $ev->RRULE = 'FREQ=YEARLY;COUNT=10'; $dtStart = new Property\DateTime('DTSTART'); $tz = new DateTimeZone('Canada/Eastern'); $dtStart->setDateTime(new DateTime('2011-01-01 13:50:20', $tz), Property\DateTime::LOCALTZ); $exDate1 = new Property\MultiDateTime('EXDATE'); $exDate1->setDateTimes(array(new DateTime('2012-01-01 13:50:20', $tz), new DateTime('2014-01-01 13:50:20', $tz)), Property\DateTime::LOCALTZ); $exDate2 = new Property\MultiDateTime('EXDATE'); $exDate2->setDateTimes(array(new DateTime('2016-01-01 13:50:20', $tz)), Property\DateTime::LOCALTZ); $ev->add($dtStart); $ev->add($exDate1); $ev->add($exDate2); $vcal = Component::create('VCALENDAR'); $vcal->add($ev); $it = new RecurrenceIterator($vcal, (string) $ev->uid); $this->assertEquals('yearly', $it->frequency); $this->assertEquals(1, $it->interval); $this->assertEquals(10, $it->count); $max = 20; $result = array(); foreach ($it as $k => $item) { $result[] = $item; $max--; if (!$max) { break; } } $this->assertEquals(array(new DateTime('2011-01-01 13:50:20', $tz), new DateTime('2013-01-01 13:50:20', $tz), new DateTime('2015-01-01 13:50:20', $tz), new DateTime('2017-01-01 13:50:20', $tz), new DateTime('2018-01-01 13:50:20', $tz), new DateTime('2019-01-01 13:50:20', $tz), new DateTime('2020-01-01 13:50:20', $tz)), $result); }
/** * Returns the type of Date format. * * This method returns one of the format constants. If no date was set, * this method will return null. * * @return int|null */ public function getDateType() { if ($this->dateType) { return $this->dateType; } if (!$this->value) { $this->dateTimes = null; $this->dateType = null; return null; } $dts = array(); foreach (explode(',', $this->value) as $val) { list($type, $dt) = DateTime::parseData($val, $this); $dts[] = $dt; $this->dateType = $type; } $this->dateTimes = $dts; return $this->dateType; }
/** * Create a Sabre\VObject\Property instance from a PHP DateTime object * * @param string Property name * @param object DateTime */ public static function datetime_prop($name, $dt, $utc = false, $dateonly = null) { $is_utc = $utc || ($tz = $dt->getTimezone()) && in_array($tz->getName(), array('UTC', 'GMT', 'Z')); $is_dateonly = $dateonly === null ? (bool) $dt->_dateonly : (bool) $dateonly; $vdt = new VObject\Property\DateTime($name); $vdt->setDateTime($dt, $is_dateonly ? VObject\Property\DateTime::DATE : ($is_utc ? VObject\Property\DateTime::UTC : VObject\Property\DateTime::LOCALTZ)); return $vdt; }
/** * @expectedException InvalidArgumentException */ function testGetDateTimeDateInvalid() { $elem = new DateTime('DTSTART', 'bla'); $dt = $elem->getDateTime(); }