4
|
1 <?php
|
|
2
|
|
3 namespace Sabre\VObject\Property;
|
|
4
|
|
5 use Sabre\VObject;
|
|
6
|
|
7 /**
|
|
8 * DateTime property
|
|
9 *
|
|
10 * This element is used for iCalendar properties such as the DTSTART property.
|
|
11 * It basically provides a few helper functions that make it easier to deal
|
|
12 * with these. It supports both DATE-TIME and DATE values.
|
|
13 *
|
|
14 * In order to use this correctly, you must call setDateTime and getDateTime to
|
|
15 * retrieve and modify dates respectively.
|
|
16 *
|
|
17 * If you use the 'value' or properties directly, this object does not keep
|
|
18 * reference and results might appear incorrectly.
|
|
19 *
|
|
20 * @copyright Copyright (C) 2007-2013 fruux GmbH (https://fruux.com/).
|
|
21 * @author Evert Pot (http://evertpot.com/)
|
|
22 * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
|
23 */
|
|
24 class DateTime extends VObject\Property {
|
|
25
|
|
26 /**
|
|
27 * Local 'floating' time
|
|
28 */
|
|
29 const LOCAL = 1;
|
|
30
|
|
31 /**
|
|
32 * UTC-based time
|
|
33 */
|
|
34 const UTC = 2;
|
|
35
|
|
36 /**
|
|
37 * Local time plus timezone
|
|
38 */
|
|
39 const LOCALTZ = 3;
|
|
40
|
|
41 /**
|
|
42 * Only a date, time is ignored
|
|
43 */
|
|
44 const DATE = 4;
|
|
45
|
|
46 /**
|
|
47 * DateTime representation
|
|
48 *
|
|
49 * @var \DateTime
|
|
50 */
|
|
51 protected $dateTime;
|
|
52
|
|
53 /**
|
|
54 * dateType
|
|
55 *
|
|
56 * @var int
|
|
57 */
|
|
58 protected $dateType;
|
|
59
|
|
60 /**
|
|
61 * Updates the Date and Time.
|
|
62 *
|
|
63 * @param \DateTime $dt
|
|
64 * @param int $dateType
|
|
65 * @return void
|
|
66 */
|
|
67 public function setDateTime(\DateTime $dt, $dateType = self::LOCALTZ) {
|
|
68
|
|
69 switch($dateType) {
|
|
70
|
|
71 case self::LOCAL :
|
|
72 $this->setValue($dt->format('Ymd\\THis'));
|
|
73 $this->offsetUnset('VALUE');
|
|
74 $this->offsetUnset('TZID');
|
|
75 $this->offsetSet('VALUE','DATE-TIME');
|
|
76 break;
|
|
77 case self::UTC :
|
|
78 $dt->setTimeZone(new \DateTimeZone('UTC'));
|
|
79 $this->setValue($dt->format('Ymd\\THis\\Z'));
|
|
80 $this->offsetUnset('VALUE');
|
|
81 $this->offsetUnset('TZID');
|
|
82 $this->offsetSet('VALUE','DATE-TIME');
|
|
83 break;
|
|
84 case self::LOCALTZ :
|
|
85 $this->setValue($dt->format('Ymd\\THis'));
|
|
86 $this->offsetUnset('VALUE');
|
|
87 $this->offsetUnset('TZID');
|
|
88 $this->offsetSet('VALUE','DATE-TIME');
|
|
89 $this->offsetSet('TZID', $dt->getTimeZone()->getName());
|
|
90 break;
|
|
91 case self::DATE :
|
|
92 $this->setValue($dt->format('Ymd'));
|
|
93 $this->offsetUnset('VALUE');
|
|
94 $this->offsetUnset('TZID');
|
|
95 $this->offsetSet('VALUE','DATE');
|
|
96 break;
|
|
97 default :
|
|
98 throw new \InvalidArgumentException('You must pass a valid dateType constant');
|
|
99
|
|
100 }
|
|
101 $this->dateTime = $dt;
|
|
102 $this->dateType = $dateType;
|
|
103
|
|
104 }
|
|
105
|
|
106 /**
|
|
107 * Returns the current DateTime value.
|
|
108 *
|
|
109 * If no value was set, this method returns null.
|
|
110 *
|
|
111 * @return \DateTime|null
|
|
112 */
|
|
113 public function getDateTime() {
|
|
114
|
|
115 if ($this->dateTime)
|
|
116 return $this->dateTime;
|
|
117
|
|
118 list(
|
|
119 $this->dateType,
|
|
120 $this->dateTime
|
|
121 ) = self::parseData($this->value, $this);
|
|
122 return $this->dateTime;
|
|
123
|
|
124 }
|
|
125
|
|
126 /**
|
|
127 * Returns the type of Date format.
|
|
128 *
|
|
129 * This method returns one of the format constants. If no date was set,
|
|
130 * this method will return null.
|
|
131 *
|
|
132 * @return int|null
|
|
133 */
|
|
134 public function getDateType() {
|
|
135
|
|
136 if ($this->dateType)
|
|
137 return $this->dateType;
|
|
138
|
|
139 list(
|
|
140 $this->dateType,
|
|
141 $this->dateTime,
|
|
142 ) = self::parseData($this->value, $this);
|
|
143 return $this->dateType;
|
|
144
|
|
145 }
|
|
146
|
|
147 /**
|
|
148 * This method will return true, if the property had a date and a time, as
|
|
149 * opposed to only a date.
|
|
150 *
|
|
151 * @return bool
|
|
152 */
|
|
153 public function hasTime() {
|
|
154
|
|
155 return $this->getDateType()!==self::DATE;
|
|
156
|
|
157 }
|
|
158
|
|
159 /**
|
|
160 * Parses the internal data structure to figure out what the current date
|
|
161 * and time is.
|
|
162 *
|
|
163 * The returned array contains two elements:
|
|
164 * 1. A 'DateType' constant (as defined on this class), or null.
|
|
165 * 2. A DateTime object (or null)
|
|
166 *
|
|
167 * @param string|null $propertyValue The string to parse (yymmdd or
|
|
168 * ymmddThhmmss, etc..)
|
|
169 * @param \Sabre\VObject\Property|null $property The instance of the
|
|
170 * property we're parsing.
|
|
171 * @return array
|
|
172 */
|
|
173 static public function parseData($propertyValue, VObject\Property $property = null) {
|
|
174
|
|
175 if (is_null($propertyValue)) {
|
|
176 return array(null, null);
|
|
177 }
|
|
178
|
|
179 $date = '(?P<year>[1-2][0-9]{3})(?P<month>[0-1][0-9])(?P<date>[0-3][0-9])';
|
|
180 $time = '(?P<hour>[0-2][0-9])(?P<minute>[0-5][0-9])(?P<second>[0-5][0-9])';
|
|
181 $regex = "/^$date(T$time(?P<isutc>Z)?)?$/";
|
|
182
|
|
183 if (!preg_match($regex, $propertyValue, $matches)) {
|
|
184 throw new \InvalidArgumentException($propertyValue . ' is not a valid \DateTime or Date string');
|
|
185 }
|
|
186
|
|
187 if (!isset($matches['hour'])) {
|
|
188 // Date-only
|
|
189 return array(
|
|
190 self::DATE,
|
|
191 new \DateTime($matches['year'] . '-' . $matches['month'] . '-' . $matches['date'] . ' 00:00:00', new \DateTimeZone('UTC')),
|
|
192 );
|
|
193 }
|
|
194
|
|
195 $dateStr =
|
|
196 $matches['year'] .'-' .
|
|
197 $matches['month'] . '-' .
|
|
198 $matches['date'] . ' ' .
|
|
199 $matches['hour'] . ':' .
|
|
200 $matches['minute'] . ':' .
|
|
201 $matches['second'];
|
|
202
|
|
203 if (isset($matches['isutc'])) {
|
|
204 $dt = new \DateTime($dateStr,new \DateTimeZone('UTC'));
|
|
205 $dt->setTimeZone(new \DateTimeZone('UTC'));
|
|
206 return array(
|
|
207 self::UTC,
|
|
208 $dt
|
|
209 );
|
|
210 }
|
|
211
|
|
212 // Finding the timezone.
|
|
213 $tzid = $property['TZID'];
|
|
214 if (!$tzid) {
|
|
215 // This was a floating time string. This implies we use the
|
|
216 // timezone from date_default_timezone_set / date.timezone ini
|
|
217 // setting.
|
|
218 return array(
|
|
219 self::LOCAL,
|
|
220 new \DateTime($dateStr)
|
|
221 );
|
|
222 }
|
|
223
|
|
224 // To look up the timezone, we must first find the VCALENDAR component.
|
|
225 $root = $property;
|
|
226 while($root->parent) {
|
|
227 $root = $root->parent;
|
|
228 }
|
|
229 if ($root->name === 'VCALENDAR') {
|
|
230 $tz = VObject\TimeZoneUtil::getTimeZone((string)$tzid, $root);
|
|
231 } else {
|
|
232 $tz = VObject\TimeZoneUtil::getTimeZone((string)$tzid);
|
|
233 }
|
|
234
|
|
235 $dt = new \DateTime($dateStr, $tz);
|
|
236 $dt->setTimeZone($tz);
|
|
237
|
|
238 return array(
|
|
239 self::LOCALTZ,
|
|
240 $dt
|
|
241 );
|
|
242
|
|
243 }
|
|
244
|
|
245 }
|