run:R W Run
25.13 KB
2026-03-11 16:18:52
R W Run
error_log
📄Date.php
1<?php
2
3// SPDX-FileCopyrightText: 2004-2023 Ryan Parman, Sam Sneddon, Ryan McCue
4// SPDX-License-Identifier: BSD-3-Clause
5
6declare(strict_types=1);
7
8namespace SimplePie\Parse;
9
10/**
11 * Date Parser
12 */
13class Date
14{
15 /**
16 * Input data
17 *
18 * @access protected
19 * @var string
20 */
21 public $date;
22
23 /**
24 * List of days, calendar day name => ordinal day number in the week
25 *
26 * @access protected
27 * @var array<string, int<1,7>>
28 */
29 public $day = [
30 // English
31 'mon' => 1,
32 'monday' => 1,
33 'tue' => 2,
34 'tuesday' => 2,
35 'wed' => 3,
36 'wednesday' => 3,
37 'thu' => 4,
38 'thursday' => 4,
39 'fri' => 5,
40 'friday' => 5,
41 'sat' => 6,
42 'saturday' => 6,
43 'sun' => 7,
44 'sunday' => 7,
45 // Dutch
46 'maandag' => 1,
47 'dinsdag' => 2,
48 'woensdag' => 3,
49 'donderdag' => 4,
50 'vrijdag' => 5,
51 'zaterdag' => 6,
52 'zondag' => 7,
53 // French
54 'lundi' => 1,
55 'mardi' => 2,
56 'mercredi' => 3,
57 'jeudi' => 4,
58 'vendredi' => 5,
59 'samedi' => 6,
60 'dimanche' => 7,
61 // German
62 'montag' => 1,
63 'mo' => 1,
64 'dienstag' => 2,
65 'di' => 2,
66 'mittwoch' => 3,
67 'mi' => 3,
68 'donnerstag' => 4,
69 'do' => 4,
70 'freitag' => 5,
71 'fr' => 5,
72 'samstag' => 6,
73 'sa' => 6,
74 'sonnabend' => 6,
75 // AFAIK no short form for sonnabend
76 'so' => 7,
77 'sonntag' => 7,
78 // Italian
79 'lunedì' => 1,
80 'martedì' => 2,
81 'mercoledì' => 3,
82 'giovedì' => 4,
83 'venerdì' => 5,
84 'sabato' => 6,
85 'domenica' => 7,
86 // Spanish
87 'lunes' => 1,
88 'martes' => 2,
89 'miércoles' => 3,
90 'jueves' => 4,
91 'viernes' => 5,
92 'sábado' => 6,
93 'domingo' => 7,
94 // Finnish
95 'maanantai' => 1,
96 'tiistai' => 2,
97 'keskiviikko' => 3,
98 'torstai' => 4,
99 'perjantai' => 5,
100 'lauantai' => 6,
101 'sunnuntai' => 7,
102 // Hungarian
103 'hétfő' => 1,
104 'kedd' => 2,
105 'szerda' => 3,
106 'csütörtok' => 4,
107 'péntek' => 5,
108 'szombat' => 6,
109 'vasárnap' => 7,
110 // Greek
111 'Δευ' => 1,
112 'Τρι' => 2,
113 'Τετ' => 3,
114 'Πεμ' => 4,
115 'Παρ' => 5,
116 'Σαβ' => 6,
117 'Κυρ' => 7,
118 // Russian
119 'Пн.' => 1,
120 'Вт.' => 2,
121 'Ср.' => 3,
122 'Чт.' => 4,
123 'Пт.' => 5,
124 'Сб.' => 6,
125 'Вс.' => 7,
126 ];
127
128 /**
129 * List of months, calendar month name => calendar month number
130 *
131 * @access protected
132 * @var array<string, int<1,12>>
133 */
134 public $month = [
135 // English
136 'jan' => 1,
137 'january' => 1,
138 'feb' => 2,
139 'february' => 2,
140 'mar' => 3,
141 'march' => 3,
142 'apr' => 4,
143 'april' => 4,
144 'may' => 5,
145 // No long form of May
146 'jun' => 6,
147 'june' => 6,
148 'jul' => 7,
149 'july' => 7,
150 'aug' => 8,
151 'august' => 8,
152 'sep' => 9,
153 'september' => 9,
154 'oct' => 10,
155 'october' => 10,
156 'nov' => 11,
157 'november' => 11,
158 'dec' => 12,
159 'december' => 12,
160 // Dutch
161 'januari' => 1,
162 'februari' => 2,
163 'maart' => 3,
164 // 'april' => 4,
165 'mei' => 5,
166 'juni' => 6,
167 'juli' => 7,
168 'augustus' => 8,
169 // 'september' => 9,
170 'oktober' => 10,
171 // 'november' => 11,
172 // 'december' => 12,
173 // French
174 'janvier' => 1,
175 'février' => 2,
176 'mars' => 3,
177 'avril' => 4,
178 'mai' => 5,
179 'juin' => 6,
180 'juillet' => 7,
181 'août' => 8,
182 'septembre' => 9,
183 'octobre' => 10,
184 'novembre' => 11,
185 'décembre' => 12,
186 // German
187 'januar' => 1,
188 // 'jan' => 1,
189 'februar' => 2,
190 // 'feb' => 2,
191 'märz' => 3,
192 'mär' => 3,
193 // 'april' => 4,
194 // 'apr' => 4,
195 // 'mai' => 5, // no short form for may
196 // 'juni' => 6,
197 // 'jun' => 6,
198 // 'juli' => 7,
199 // 'jul' => 7,
200 // 'august' => 8,
201 // 'aug' => 8,
202 // 'september' => 9,
203 // 'sep' => 9,
204 // 'oktober' => 10,
205 'okt' => 10,
206 // 'november' => 11,
207 // 'nov' => 11,
208 'dezember' => 12,
209 'dez' => 12,
210 // Italian
211 'gennaio' => 1,
212 'febbraio' => 2,
213 'marzo' => 3,
214 'aprile' => 4,
215 'maggio' => 5,
216 'giugno' => 6,
217 'luglio' => 7,
218 'agosto' => 8,
219 'settembre' => 9,
220 'ottobre' => 10,
221 // 'novembre' => 11,
222 'dicembre' => 12,
223 // Spanish
224 'enero' => 1,
225 'febrero' => 2,
226 // 'marzo' => 3,
227 'abril' => 4,
228 'mayo' => 5,
229 'junio' => 6,
230 'julio' => 7,
231 // 'agosto' => 8,
232 'septiembre' => 9,
233 'setiembre' => 9,
234 'octubre' => 10,
235 'noviembre' => 11,
236 'diciembre' => 12,
237 // Finnish
238 'tammikuu' => 1,
239 'helmikuu' => 2,
240 'maaliskuu' => 3,
241 'huhtikuu' => 4,
242 'toukokuu' => 5,
243 'kesäkuu' => 6,
244 'heinäkuu' => 7,
245 'elokuu' => 8,
246 'suuskuu' => 9,
247 'lokakuu' => 10,
248 'marras' => 11,
249 'joulukuu' => 12,
250 // Hungarian
251 'január' => 1,
252 'február' => 2,
253 'március' => 3,
254 'április' => 4,
255 'május' => 5,
256 'június' => 6,
257 'július' => 7,
258 'augusztus' => 8,
259 'szeptember' => 9,
260 'október' => 10,
261 // 'november' => 11,
262 // 'december' => 12,
263 // Greek
264 'Ιαν' => 1,
265 'Φεβ' => 2,
266 'Μάώ' => 3,
267 'Μαώ' => 3,
268 'Απρ' => 4,
269 'Μάι' => 5,
270 'Μαϊ' => 5,
271 'Μαι' => 5,
272 'Ιούν' => 6,
273 'Ιον' => 6,
274 'Ιούλ' => 7,
275 'Ιολ' => 7,
276 'Αύγ' => 8,
277 'Αυγ' => 8,
278 'Σεπ' => 9,
279 'Οκτ' => 10,
280 'Νοέ' => 11,
281 'Δεκ' => 12,
282 // Russian
283 'Янв' => 1,
284 'января' => 1,
285 'Фев' => 2,
286 'февраля' => 2,
287 'Мар' => 3,
288 'марта' => 3,
289 'Апр' => 4,
290 'апреля' => 4,
291 'Май' => 5,
292 'мая' => 5,
293 'Июн' => 6,
294 'июня' => 6,
295 'Июл' => 7,
296 'июля' => 7,
297 'Авг' => 8,
298 'августа' => 8,
299 'Сен' => 9,
300 'сентября' => 9,
301 'Окт' => 10,
302 'октября' => 10,
303 'Ноя' => 11,
304 'ноября' => 11,
305 'Дек' => 12,
306 'декабря' => 12,
307
308 ];
309
310 /**
311 * List of timezones, abbreviation => offset from UTC
312 *
313 * @access protected
314 * @var array<string, int>
315 */
316 public $timezone = [
317 'ACDT' => 37800,
318 'ACIT' => 28800,
319 'ACST' => 34200,
320 'ACT' => -18000,
321 'ACWDT' => 35100,
322 'ACWST' => 31500,
323 'AEDT' => 39600,
324 'AEST' => 36000,
325 'AFT' => 16200,
326 'AKDT' => -28800,
327 'AKST' => -32400,
328 'AMDT' => 18000,
329 'AMT' => -14400,
330 'ANAST' => 46800,
331 'ANAT' => 43200,
332 'ART' => -10800,
333 'AZOST' => -3600,
334 'AZST' => 18000,
335 'AZT' => 14400,
336 'BIOT' => 21600,
337 'BIT' => -43200,
338 'BOT' => -14400,
339 'BRST' => -7200,
340 'BRT' => -10800,
341 'BST' => 3600,
342 'BTT' => 21600,
343 'CAST' => 18000,
344 'CAT' => 7200,
345 'CCT' => 23400,
346 'CDT' => -18000,
347 'CEDT' => 7200,
348 'CEST' => 7200,
349 'CET' => 3600,
350 'CGST' => -7200,
351 'CGT' => -10800,
352 'CHADT' => 49500,
353 'CHAST' => 45900,
354 'CIST' => -28800,
355 'CKT' => -36000,
356 'CLDT' => -10800,
357 'CLST' => -14400,
358 'COT' => -18000,
359 'CST' => -21600,
360 'CVT' => -3600,
361 'CXT' => 25200,
362 'DAVT' => 25200,
363 'DTAT' => 36000,
364 'EADT' => -18000,
365 'EAST' => -21600,
366 'EAT' => 10800,
367 'ECT' => -18000,
368 'EDT' => -14400,
369 'EEST' => 10800,
370 'EET' => 7200,
371 'EGT' => -3600,
372 'EKST' => 21600,
373 'EST' => -18000,
374 'FJT' => 43200,
375 'FKDT' => -10800,
376 'FKST' => -14400,
377 'FNT' => -7200,
378 'GALT' => -21600,
379 'GEDT' => 14400,
380 'GEST' => 10800,
381 'GFT' => -10800,
382 'GILT' => 43200,
383 'GIT' => -32400,
384 'GST' => 14400,
385 // 'GST' => -7200,
386 'GYT' => -14400,
387 'HAA' => -10800,
388 'HAC' => -18000,
389 'HADT' => -32400,
390 'HAE' => -14400,
391 'HAP' => -25200,
392 'HAR' => -21600,
393 'HAST' => -36000,
394 'HAT' => -9000,
395 'HAY' => -28800,
396 'HKST' => 28800,
397 'HMT' => 18000,
398 'HNA' => -14400,
399 'HNC' => -21600,
400 'HNE' => -18000,
401 'HNP' => -28800,
402 'HNR' => -25200,
403 'HNT' => -12600,
404 'HNY' => -32400,
405 'IRDT' => 16200,
406 'IRKST' => 32400,
407 'IRKT' => 28800,
408 'IRST' => 12600,
409 'JFDT' => -10800,
410 'JFST' => -14400,
411 'JST' => 32400,
412 'KGST' => 21600,
413 'KGT' => 18000,
414 'KOST' => 39600,
415 'KOVST' => 28800,
416 'KOVT' => 25200,
417 'KRAST' => 28800,
418 'KRAT' => 25200,
419 'KST' => 32400,
420 'LHDT' => 39600,
421 'LHST' => 37800,
422 'LINT' => 50400,
423 'LKT' => 21600,
424 'MAGST' => 43200,
425 'MAGT' => 39600,
426 'MAWT' => 21600,
427 'MDT' => -21600,
428 'MESZ' => 7200,
429 'MEZ' => 3600,
430 'MHT' => 43200,
431 'MIT' => -34200,
432 'MNST' => 32400,
433 'MSDT' => 14400,
434 'MSST' => 10800,
435 'MST' => -25200,
436 'MUT' => 14400,
437 'MVT' => 18000,
438 'MYT' => 28800,
439 'NCT' => 39600,
440 'NDT' => -9000,
441 'NFT' => 41400,
442 'NMIT' => 36000,
443 'NOVST' => 25200,
444 'NOVT' => 21600,
445 'NPT' => 20700,
446 'NRT' => 43200,
447 'NST' => -12600,
448 'NUT' => -39600,
449 'NZDT' => 46800,
450 'NZST' => 43200,
451 'OMSST' => 25200,
452 'OMST' => 21600,
453 'PDT' => -25200,
454 'PET' => -18000,
455 'PETST' => 46800,
456 'PETT' => 43200,
457 'PGT' => 36000,
458 'PHOT' => 46800,
459 'PHT' => 28800,
460 'PKT' => 18000,
461 'PMDT' => -7200,
462 'PMST' => -10800,
463 'PONT' => 39600,
464 'PST' => -28800,
465 'PWT' => 32400,
466 'PYST' => -10800,
467 'PYT' => -14400,
468 'RET' => 14400,
469 'ROTT' => -10800,
470 'SAMST' => 18000,
471 'SAMT' => 14400,
472 'SAST' => 7200,
473 'SBT' => 39600,
474 'SCDT' => 46800,
475 'SCST' => 43200,
476 'SCT' => 14400,
477 'SEST' => 3600,
478 'SGT' => 28800,
479 'SIT' => 28800,
480 'SRT' => -10800,
481 'SST' => -39600,
482 'SYST' => 10800,
483 'SYT' => 7200,
484 'TFT' => 18000,
485 'THAT' => -36000,
486 'TJT' => 18000,
487 'TKT' => -36000,
488 'TMT' => 18000,
489 'TOT' => 46800,
490 'TPT' => 32400,
491 'TRUT' => 36000,
492 'TVT' => 43200,
493 'TWT' => 28800,
494 'UYST' => -7200,
495 'UYT' => -10800,
496 'UZT' => 18000,
497 'VET' => -14400,
498 'VLAST' => 39600,
499 'VLAT' => 36000,
500 'VOST' => 21600,
501 'VUT' => 39600,
502 'WAST' => 7200,
503 'WAT' => 3600,
504 'WDT' => 32400,
505 'WEST' => 3600,
506 'WFT' => 43200,
507 'WIB' => 25200,
508 'WIT' => 32400,
509 'WITA' => 28800,
510 'WKST' => 18000,
511 'WST' => 28800,
512 'YAKST' => 36000,
513 'YAKT' => 32400,
514 'YAPT' => 36000,
515 'YEKST' => 21600,
516 'YEKT' => 18000,
517 ];
518
519 /**
520 * Cached PCRE for Date::$day
521 *
522 * @access protected
523 * @var string
524 */
525 public $day_pcre;
526
527 /**
528 * Cached PCRE for Date::$month
529 *
530 * @access protected
531 * @var string
532 */
533 public $month_pcre;
534
535 /**
536 * Array of user-added callback methods
537 *
538 * @access private
539 * @var array<string>
540 */
541 public $built_in = [];
542
543 /**
544 * Array of user-added callback methods
545 *
546 * @access private
547 * @var array<callable(string): (int|false)>
548 */
549 public $user = [];
550
551 /**
552 * Create new Date object, and set self::day_pcre,
553 * self::month_pcre, and self::built_in
554 *
555 * @access private
556 */
557 public function __construct()
558 {
559 $this->day_pcre = '(' . implode('|', array_keys($this->day)) . ')';
560 $this->month_pcre = '(' . implode('|', array_keys($this->month)) . ')';
561
562 static $cache;
563 if (!isset($cache[get_class($this)])) {
564 $all_methods = get_class_methods($this);
565
566 foreach ($all_methods as $method) {
567 if (strtolower(substr($method, 0, 5)) === 'date_') {
568 $cache[get_class($this)][] = $method;
569 }
570 }
571 }
572
573 foreach ($cache[get_class($this)] as $method) {
574 $this->built_in[] = $method;
575 }
576 }
577
578 /**
579 * Get the object
580 *
581 * @access public
582 * @return Date
583 */
584 public static function get()
585 {
586 static $object;
587 if (!$object) {
588 $object = new Date();
589 }
590 return $object;
591 }
592
593 /**
594 * Parse a date
595 *
596 * @final
597 * @access public
598 * @param string $date Date to parse
599 * @return int|false Timestamp corresponding to date string, or false on failure
600 */
601 public function parse(string $date)
602 {
603 foreach ($this->user as $method) {
604 if (($returned = call_user_func($method, $date)) !== false) {
605 return (int) $returned;
606 }
607 }
608
609 foreach ($this->built_in as $method) {
610 // TODO: we should really check this in constructor but that would require private properties.
611 /** @var callable(string): (int|false) */
612 $callable = [$this, $method];
613 if (($returned = call_user_func($callable, $date)) !== false) {
614 return $returned;
615 }
616 }
617
618 return false;
619 }
620
621 /**
622 * Add a callback method to parse a date
623 *
624 * @final
625 * @access public
626 * @param callable $callback
627 * @return void
628 */
629 public function add_callback(callable $callback)
630 {
631 $this->user[] = $callback;
632 }
633
634 /**
635 * Parse a superset of W3C-DTF (allows hyphens and colons to be omitted, as
636 * well as allowing any of upper or lower case "T", horizontal tabs, or
637 * spaces to be used as the time separator (including more than one))
638 *
639 * @access protected
640 * @param string $date
641 * @return int|false Timestamp
642 */
643 public function date_w3cdtf(string $date)
644 {
645 $pcre = <<<'PCRE'
646 /
647 ^
648 (?P<year>[0-9]{4})
649 (?:
650 -?
651 (?P<month>[0-9]{2})
652 (?:
653 -?
654 (?P<day>[0-9]{2})
655 (?:
656 [Tt\x09\x20]+
657 (?P<hour>[0-9]{2})
658 (?:
659 :?
660 (?P<minute>[0-9]{2})
661 (?:
662 :?
663 (?P<second>[0-9]{2})
664 (?:
665 .
666 (?P<second_fraction>[0-9]*)
667 )?
668 )?
669 )?
670 (?:
671 (?P<zulu>Z)
672 | (?P<tz_sign>[+\-])
673 (?P<tz_hour>[0-9]{1,2})
674 :?
675 (?P<tz_minute>[0-9]{1,2})
676 )
677 )?
678 )?
679 )?
680 $
681 /x
682PCRE;
683 if (preg_match($pcre, $date, $match)) {
684 // Fill in empty matches and convert to proper types.
685 $year = (int) $match['year'];
686 $month = isset($match['month']) ? (int) $match['month'] : 1;
687 $day = isset($match['day']) ? (int) $match['day'] : 1;
688 $hour = isset($match['hour']) ? (int) $match['hour'] : 0;
689 $minute = isset($match['minute']) ? (int) $match['minute'] : 0;
690 $second = isset($match['second']) ? (int) $match['second'] : 0;
691 $second_fraction = isset($match['second_fraction']) ? ((int) $match['second_fraction']) / (10 ** strlen($match['second_fraction'])) : 0;
692 $tz_sign = ($match['tz_sign'] ?? '') === '-' ? -1 : 1;
693 $tz_hour = isset($match['tz_hour']) ? (int) $match['tz_hour'] : 0;
694 $tz_minute = isset($match['tz_minute']) ? (int) $match['tz_minute'] : 0;
695
696 // Numeric timezone
697 $timezone = $tz_hour * 3600;
698 $timezone += $tz_minute * 60;
699 $timezone *= $tz_sign;
700
701 // Convert the number of seconds to an integer, taking decimals into account
702 $second = (int) round($second + $second_fraction);
703
704 return gmmktime($hour, $minute, $second, $month, $day, $year) - $timezone;
705 }
706
707 return false;
708 }
709
710 /**
711 * Remove RFC822 comments
712 *
713 * @access protected
714 * @param string $string Data to strip comments from
715 * @return string Comment stripped string
716 */
717 public function remove_rfc2822_comments(string $string)
718 {
719 $position = 0;
720 $length = strlen($string);
721 $depth = 0;
722
723 $output = '';
724
725 while ($position < $length && ($pos = strpos($string, '(', $position)) !== false) {
726 $output .= substr($string, $position, $pos - $position);
727 $position = $pos + 1;
728 if ($pos === 0 || $string[$pos - 1] !== '\\') {
729 $depth++;
730 while ($depth && $position < $length) {
731 $position += strcspn($string, '()', $position);
732 if ($string[$position - 1] === '\\') {
733 $position++;
734 continue;
735 } elseif (isset($string[$position])) {
736 switch ($string[$position]) {
737 case '(':
738 $depth++;
739 break;
740
741 case ')':
742 $depth--;
743 break;
744 }
745 $position++;
746 } else {
747 break;
748 }
749 }
750 } else {
751 $output .= '(';
752 }
753 }
754 $output .= substr($string, $position);
755
756 return $output;
757 }
758
759 /**
760 * Parse RFC2822's date format
761 *
762 * @access protected
763 * @param string $date
764 * @return int|false Timestamp
765 */
766 public function date_rfc2822(string $date)
767 {
768 static $pcre;
769 if (!$pcre) {
770 $wsp = '[\x09\x20]';
771 $fws = '(?:' . $wsp . '+|' . $wsp . '*(?:\x0D\x0A' . $wsp . '+)+)';
772 $optional_fws = $fws . '?';
773 $day_name = $this->day_pcre;
774 $month = $this->month_pcre;
775 $day = '([0-9]{1,2})';
776 $hour = $minute = $second = '([0-9]{2})';
777 $year = '([0-9]{2,4})';
778 $num_zone = '([+\-])([0-9]{2})([0-9]{2})';
779 $character_zone = '([A-Z]{1,5})';
780 $zone = '(?:' . $num_zone . '|' . $character_zone . ')';
781 $pcre = '/(?:' . $optional_fws . $day_name . $optional_fws . ',)?' . $optional_fws . $day . $fws . $month . $fws . $year . $fws . $hour . $optional_fws . ':' . $optional_fws . $minute . '(?:' . $optional_fws . ':' . $optional_fws . $second . ')?' . $fws . $zone . '/i';
782 }
783 if (preg_match($pcre, $this->remove_rfc2822_comments($date), $match)) {
784 /*
785 Capturing subpatterns:
786 1: Day name
787 2: Day
788 3: Month
789 4: Year
790 5: Hour
791 6: Minute
792 7: Second
793 8: Timezone ±
794 9: Timezone hours
795 10: Timezone minutes
796 11: Alphabetic timezone
797 */
798
799 $day = (int) $match[2];
800 // Find the month number
801 $month = $this->month[strtolower($match[3])];
802 $year = (int) $match[4];
803 $hour = (int) $match[5];
804 $minute = (int) $match[6];
805 // Second is optional, if it is empty set it to zero
806 $second = (int) $match[7];
807
808 $tz_sign = $match[8];
809 $tz_hour = (int) $match[9];
810 $tz_minute = (int) $match[10];
811 $tz_code = isset($match[11]) ? strtoupper($match[11]) : '';
812
813 // Numeric timezone
814 if ($tz_sign !== '') {
815 $timezone = $tz_hour * 3600;
816 $timezone += $tz_minute * 60;
817 if ($tz_sign === '-') {
818 $timezone = 0 - $timezone;
819 }
820 }
821 // Character timezone
822 elseif (isset($this->timezone[$tz_code])) {
823 $timezone = $this->timezone[$tz_code];
824 }
825 // Assume everything else to be -0000
826 else {
827 $timezone = 0;
828 }
829
830 // Deal with 2/3 digit years
831 if ($year < 50) {
832 $year += 2000;
833 } elseif ($year < 1000) {
834 $year += 1900;
835 }
836
837 return gmmktime($hour, $minute, $second, $month, $day, $year) - $timezone;
838 }
839
840 return false;
841 }
842
843 /**
844 * Parse RFC850's date format
845 *
846 * @access protected
847 * @param string $date
848 * @return int|false Timestamp
849 */
850 public function date_rfc850(string $date)
851 {
852 static $pcre;
853 if (!$pcre) {
854 $space = '[\x09\x20]+';
855 $day_name = $this->day_pcre;
856 $month = $this->month_pcre;
857 $day = '([0-9]{1,2})';
858 $year = $hour = $minute = $second = '([0-9]{2})';
859 $zone = '([A-Z]{1,5})';
860 $pcre = '/^' . $day_name . ',' . $space . $day . '-' . $month . '-' . $year . $space . $hour . ':' . $minute . ':' . $second . $space . $zone . '$/i';
861 }
862 if (preg_match($pcre, $date, $match)) {
863 /*
864 Capturing subpatterns:
865 1: Day name
866 2: Day
867 3: Month
868 4: Year
869 5: Hour
870 6: Minute
871 7: Second
872 8: Timezone
873 */
874
875 $day = (int) $match[2];
876 // Month
877 $month = $this->month[strtolower($match[3])];
878 $year = (int) $match[4];
879 $hour = (int) $match[5];
880 $minute = (int) $match[6];
881 // Second is optional, if it is empty set it to zero
882 $second = (int) $match[7];
883
884 $tz_code = strtoupper($match[8]);
885
886 // Character timezone
887 if (isset($this->timezone[$tz_code])) {
888 $timezone = $this->timezone[$tz_code];
889 }
890 // Assume everything else to be -0000
891 else {
892 $timezone = 0;
893 }
894
895 // Deal with 2 digit year
896 if ($year < 50) {
897 $year += 2000;
898 } else {
899 $year += 1900;
900 }
901
902 return gmmktime($hour, $minute, $second, $month, $day, $year) - $timezone;
903 }
904
905 return false;
906 }
907
908 /**
909 * Parse C99's asctime()'s date format
910 *
911 * @access protected
912 * @param string $date
913 * @return int|false Timestamp
914 */
915 public function date_asctime(string $date)
916 {
917 static $pcre;
918 if (!$pcre) {
919 $space = '[\x09\x20]+';
920 $wday_name = $this->day_pcre;
921 $mon_name = $this->month_pcre;
922 $day = '([0-9]{1,2})';
923 $hour = $sec = $min = '([0-9]{2})';
924 $year = '([0-9]{4})';
925 $terminator = '\x0A?\x00?';
926 $pcre = '/^' . $wday_name . $space . $mon_name . $space . $day . $space . $hour . ':' . $min . ':' . $sec . $space . $year . $terminator . '$/i';
927 }
928 if (preg_match($pcre, $date, $match)) {
929 /*
930 Capturing subpatterns:
931 1: Day name
932 2: Month
933 3: Day
934 4: Hour
935 5: Minute
936 6: Second
937 7: Year
938 */
939
940 $month = $this->month[strtolower($match[2])];
941 return gmmktime((int) $match[4], (int) $match[5], (int) $match[6], $month, (int) $match[3], (int) $match[7]);
942 }
943
944 return false;
945 }
946
947 /**
948 * Parse dates using strtotime()
949 *
950 * @access protected
951 * @param string $date
952 * @return int|false Timestamp
953 */
954 public function date_strtotime(string $date)
955 {
956 $strtotime = strtotime($date);
957 if ($strtotime === -1 || $strtotime === false) {
958 return false;
959 }
960
961 return $strtotime;
962 }
963}
964
965class_alias('SimplePie\Parse\Date', 'SimplePie_Parse_Date');
966