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