ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
DateTimeParser.php
Go to the documentation of this file.
1<?php
2
3namespace Sabre\VObject;
4
5use DateInterval;
6use DateTimeImmutable;
7use DateTimeZone;
8
20
34 static function parseDateTime($dt, DateTimeZone $tz = null) {
35
36 // Format is YYYYMMDD + "T" + hhmmss
37 $result = preg_match('/^([0-9]{4})([0-1][0-9])([0-3][0-9])T([0-2][0-9])([0-5][0-9])([0-5][0-9])([Z]?)$/', $dt, $matches);
38
39 if (!$result) {
40 throw new InvalidDataException('The supplied iCalendar datetime value is incorrect: ' . $dt);
41 }
42
43 if ($matches[7] === 'Z' || is_null($tz)) {
44 $tz = new DateTimeZone('UTC');
45 }
46
47 try {
48 $date = new DateTimeImmutable($matches[1] . '-' . $matches[2] . '-' . $matches[3] . ' ' . $matches[4] . ':' . $matches[5] . ':' . $matches[6], $tz);
49 } catch (\Exception $e) {
50 throw new InvalidDataException('The supplied iCalendar datetime value is incorrect: ' . $dt);
51 }
52
53 return $date;
54
55 }
56
65 static function parseDate($date, DateTimeZone $tz = null) {
66
67 // Format is YYYYMMDD
68 $result = preg_match('/^([0-9]{4})([0-1][0-9])([0-3][0-9])$/', $date, $matches);
69
70 if (!$result) {
71 throw new InvalidDataException('The supplied iCalendar date value is incorrect: ' . $date);
72 }
73
74 if (is_null($tz)) {
75 $tz = new DateTimeZone('UTC');
76 }
77
78 try {
79 $date = new DateTimeImmutable($matches[1] . '-' . $matches[2] . '-' . $matches[3], $tz);
80 } catch (\Exception $e) {
81 throw new InvalidDataException('The supplied iCalendar date value is incorrect: ' . $date);
82 }
83
84 return $date;
85
86 }
87
99 static function parseDuration($duration, $asString = false) {
100
101 $result = preg_match('/^(?<plusminus>\+|-)?P((?<week>\d+)W)?((?<day>\d+)D)?(T((?<hour>\d+)H)?((?<minute>\d+)M)?((?<second>\d+)S)?)?$/', $duration, $matches);
102 if (!$result) {
103 throw new InvalidDataException('The supplied iCalendar duration value is incorrect: ' . $duration);
104 }
105
106 if (!$asString) {
107
108 $invert = false;
109
110 if ($matches['plusminus'] === '-') {
111 $invert = true;
112 }
113
114 $parts = [
115 'week',
116 'day',
117 'hour',
118 'minute',
119 'second',
120 ];
121
122 foreach ($parts as $part) {
123 $matches[$part] = isset($matches[$part]) && $matches[$part] ? (int)$matches[$part] : 0;
124 }
125
126 // We need to re-construct the $duration string, because weeks and
127 // days are not supported by DateInterval in the same string.
128 $duration = 'P';
129 $days = $matches['day'];
130
131 if ($matches['week']) {
132 $days += $matches['week'] * 7;
133 }
134
135 if ($days) {
136 $duration .= $days . 'D';
137 }
138
139 if ($matches['minute'] || $matches['second'] || $matches['hour']) {
140
141 $duration .= 'T';
142
143 if ($matches['hour']) {
144 $duration .= $matches['hour'] . 'H';
145 }
146
147 if ($matches['minute']) {
148 $duration .= $matches['minute'] . 'M';
149 }
150
151 if ($matches['second']) {
152 $duration .= $matches['second'] . 'S';
153 }
154
155 }
156
157 if ($duration === 'P') {
158 $duration = 'PT0S';
159 }
160
161 $iv = new DateInterval($duration);
162
163 if ($invert) {
164 $iv->invert = true;
165 }
166
167 return $iv;
168
169 }
170
171 $parts = [
172 'week',
173 'day',
174 'hour',
175 'minute',
176 'second',
177 ];
178
179 $newDur = '';
180
181 foreach ($parts as $part) {
182 if (isset($matches[$part]) && $matches[$part]) {
183 $newDur .= ' ' . $matches[$part] . ' ' . $part . 's';
184 }
185 }
186
187 $newDur = ($matches['plusminus'] === '-' ? '-' : '+') . trim($newDur);
188
189 if ($newDur === '+') {
190 $newDur = '+0 seconds';
191 };
192
193 return $newDur;
194
195 }
196
205 static function parse($date, $referenceTz = null) {
206
207 if ($date[0] === 'P' || ($date[0] === '-' && $date[1] === 'P')) {
208 return self::parseDuration($date);
209 } elseif (strlen($date) === 8) {
210 return self::parseDate($date, $referenceTz);
211 } else {
212 return self::parseDateTime($date, $referenceTz);
213 }
214
215 }
216
273 static function parseVCardDateTime($date) {
274
275 $regex = '/^
276 (?: # date part
277 (?:
278 (?: (?<year> [0-9]{4}) (?: -)?| --)
279 (?<month> [0-9]{2})?
280 |---)
281 (?<date> [0-9]{2})?
282 )?
283 (?:T # time part
284 (?<hour> [0-9]{2} | -)
285 (?<minute> [0-9]{2} | -)?
286 (?<second> [0-9]{2})?
287
288 (?: \.[0-9]{3})? # milliseconds
289 (?P<timezone> # timezone offset
290
291 Z | (?: \+|-)(?: [0-9]{4})
292
293 )?
294
295 )?
296 $/x';
297
298 if (!preg_match($regex, $date, $matches)) {
299
300 // Attempting to parse the extended format.
301 $regex = '/^
302 (?: # date part
303 (?: (?<year> [0-9]{4}) - | -- )
304 (?<month> [0-9]{2}) -
305 (?<date> [0-9]{2})
306 )?
307 (?:T # time part
308
309 (?: (?<hour> [0-9]{2}) : | -)
310 (?: (?<minute> [0-9]{2}) : | -)?
311 (?<second> [0-9]{2})?
312
313 (?: \.[0-9]{3})? # milliseconds
314 (?P<timezone> # timezone offset
315
316 Z | (?: \+|-)(?: [0-9]{2}:[0-9]{2})
317
318 )?
319
320 )?
321 $/x';
322
323 if (!preg_match($regex, $date, $matches)) {
324 throw new InvalidDataException('Invalid vCard date-time string: ' . $date);
325 }
326
327 }
328 $parts = [
329 'year',
330 'month',
331 'date',
332 'hour',
333 'minute',
334 'second',
335 'timezone'
336 ];
337
338 $result = [];
339 foreach ($parts as $part) {
340
341 if (empty($matches[$part])) {
342 $result[$part] = null;
343 } elseif ($matches[$part] === '-' || $matches[$part] === '--') {
344 $result[$part] = null;
345 } else {
346 $result[$part] = $matches[$part];
347 }
348
349 }
350
351 return $result;
352
353 }
354
397 static function parseVCardTime($date) {
398
399 $regex = '/^
400 (?<hour> [0-9]{2} | -)
401 (?<minute> [0-9]{2} | -)?
402 (?<second> [0-9]{2})?
403
404 (?: \.[0-9]{3})? # milliseconds
405 (?P<timezone> # timezone offset
406
407 Z | (?: \+|-)(?: [0-9]{4})
408
409 )?
410 $/x';
411
412
413 if (!preg_match($regex, $date, $matches)) {
414
415 // Attempting to parse the extended format.
416 $regex = '/^
417 (?: (?<hour> [0-9]{2}) : | -)
418 (?: (?<minute> [0-9]{2}) : | -)?
419 (?<second> [0-9]{2})?
420
421 (?: \.[0-9]{3})? # milliseconds
422 (?P<timezone> # timezone offset
423
424 Z | (?: \+|-)(?: [0-9]{2}:[0-9]{2})
425
426 )?
427 $/x';
428
429 if (!preg_match($regex, $date, $matches)) {
430 throw new InvalidDataException('Invalid vCard time string: ' . $date);
431 }
432
433 }
434 $parts = [
435 'hour',
436 'minute',
437 'second',
438 'timezone'
439 ];
440
441 $result = [];
442 foreach ($parts as $part) {
443
444 if (empty($matches[$part])) {
445 $result[$part] = null;
446 } elseif ($matches[$part] === '-') {
447 $result[$part] = null;
448 } else {
449 $result[$part] = $matches[$part];
450 }
451
452 }
453
454 return $result;
455
456 }
457
509 static function parseVCardDateAndOrTime($date) {
510
511 // \d{8}|\d{4}-\d\d|--\d\d(\d\d)?|---\d\d
512 $valueDate = '/^(?J)(?:' .
513 '(?<year>\d{4})(?<month>\d\d)(?<date>\d\d)' .
514 '|(?<year>\d{4})-(?<month>\d\d)' .
515 '|--(?<month>\d\d)(?<date>\d\d)?' .
516 '|---(?<date>\d\d)' .
517 ')$/';
518
519 // (\d\d(\d\d(\d\d)?)?|-\d\d(\d\d)?|--\d\d)(Z|[+\-]\d\d(\d\d)?)?
520 $valueTime = '/^(?J)(?:' .
521 '((?<hour>\d\d)((?<minute>\d\d)(?<second>\d\d)?)?' .
522 '|-(?<minute>\d\d)(?<second>\d\d)?' .
523 '|--(?<second>\d\d))' .
524 '(?<timezone>(Z|[+\-]\d\d(\d\d)?))?' .
525 ')$/';
526
527 // (\d{8}|--\d{4}|---\d\d)T\d\d(\d\d(\d\d)?)?(Z|[+\-]\d\d(\d\d?)?
528 $valueDateTime = '/^(?:' .
529 '((?<year0>\d{4})(?<month0>\d\d)(?<date0>\d\d)' .
530 '|--(?<month1>\d\d)(?<date1>\d\d)' .
531 '|---(?<date2>\d\d))' .
532 'T' .
533 '(?<hour>\d\d)((?<minute>\d\d)(?<second>\d\d)?)?' .
534 '(?<timezone>(Z|[+\-]\d\d(\d\d?)))?' .
535 ')$/';
536
537 // date-and-or-time is date | date-time | time
538 // in this strict order.
539
540 if (0 === preg_match($valueDate, $date, $matches)
541 && 0 === preg_match($valueDateTime, $date, $matches)
542 && 0 === preg_match($valueTime, $date, $matches)) {
543 throw new InvalidDataException('Invalid vCard date-time string: ' . $date);
544 }
545
546 $parts = [
547 'year' => null,
548 'month' => null,
549 'date' => null,
550 'hour' => null,
551 'minute' => null,
552 'second' => null,
553 'timezone' => null
554 ];
555
556 // The $valueDateTime expression has a bug with (?J) so we simulate it.
557 $parts['date0'] = &$parts['date'];
558 $parts['date1'] = &$parts['date'];
559 $parts['date2'] = &$parts['date'];
560 $parts['month0'] = &$parts['month'];
561 $parts['month1'] = &$parts['month'];
562 $parts['year0'] = &$parts['year'];
563
564 foreach ($parts as $part => &$value) {
565 if (!empty($matches[$part])) {
566 $value = $matches[$part];
567 }
568 }
569
570 unset($parts['date0']);
571 unset($parts['date1']);
572 unset($parts['date2']);
573 unset($parts['month0']);
574 unset($parts['month1']);
575 unset($parts['year0']);
576
577 return $parts;
578
579 }
580}
$result
An exception for terminatinating execution or to throw for unit testing.
static parseVCardDateTime($date)
This method parses a vCard date and or time value.
static parseVCardDateAndOrTime($date)
This method parses a vCard date and or time value.
static parse($date, $referenceTz=null)
Parses either a Date or DateTime, or Duration value.
static parseDuration($duration, $asString=false)
Parses an iCalendar (RFC5545) formatted duration value.
static parseDateTime($dt, DateTimeZone $tz=null)
Parses an iCalendar (rfc5545) formatted datetime and returns a DateTimeImmutable object.
static parseVCardTime($date)
This method parses a vCard TIME value.
static parseDate($date, DateTimeZone $tz=null)
Parses an iCalendar (rfc5545) formatted date and returns a DateTimeImmutable object.
This exception is thrown whenever an invalid value is found anywhere in a iCalendar or vCard object.