ordinal day number in the week * * @access protected * @var array */ var $day = array( // English 'mon' => 1, 'monday' => 1, 'tue' => 2, 'tuesday' => 2, 'wed' => 3, 'wednesday' => 3, 'thu' => 4, 'thursday' => 4, 'fri' => 5, 'friday' => 5, 'sat' => 6, 'saturday' => 6, 'sun' => 7, 'sunday' => 7, // Dutch 'maandag' => 1, 'dinsdag' => 2, 'woensdag' => 3, 'donderdag' => 4, 'vrijdag' => 5, 'zaterdag' => 6, 'zondag' => 7, // French 'lundi' => 1, 'mardi' => 2, 'mercredi' => 3, 'jeudi' => 4, 'vendredi' => 5, 'samedi' => 6, 'dimanche' => 7, // German 'montag' => 1, 'mo' => 1, 'dienstag' => 2, 'di' => 2, 'mittwoch' => 3, 'mi' => 3, 'donnerstag' => 4, 'do' => 4, 'freitag' => 5, 'fr' => 5, 'samstag' => 6, 'sa' => 6, 'sonnabend' => 6, // AFAIK no short form for sonnabend 'so' => 7, 'sonntag' => 7, // Italian 'lunedì' => 1, 'martedì' => 2, 'mercoledì' => 3, 'giovedì' => 4, 'venerdì' => 5, 'sabato' => 6, 'domenica' => 7, // Spanish 'lunes' => 1, 'martes' => 2, 'miércoles' => 3, 'jueves' => 4, 'viernes' => 5, 'sábado' => 6, 'domingo' => 7, // Finnish 'maanantai' => 1, 'tiistai' => 2, 'keskiviikko' => 3, 'torstai' => 4, 'perjantai' => 5, 'lauantai' => 6, 'sunnuntai' => 7, // Hungarian 'hétfő' => 1, 'kedd' => 2, 'szerda' => 3, 'csütörtok' => 4, 'péntek' => 5, 'szombat' => 6, 'vasárnap' => 7, // Greek 'Δευ' => 1, 'Τρι' => 2, 'Τετ' => 3, 'Πεμ' => 4, 'Παρ' => 5, 'Σαβ' => 6, 'Κυρ' => 7, // Russian 'Пн.' => 1, 'Вт.' => 2, 'Ср.' => 3, 'Чт.' => 4, 'Пт.' => 5, 'Сб.' => 6, 'Вс.' => 7, ); /** * List of months, calendar month name => calendar month number * * @access protected * @var array */ var $month = array( // English 'jan' => 1, 'january' => 1, 'feb' => 2, 'february' => 2, 'mar' => 3, 'march' => 3, 'apr' => 4, 'april' => 4, 'may' => 5, // No long form of May 'jun' => 6, 'june' => 6, 'jul' => 7, 'july' => 7, 'aug' => 8, 'august' => 8, 'sep' => 9, 'september' => 9, 'oct' => 10, 'october' => 10, 'nov' => 11, 'november' => 11, 'dec' => 12, 'december' => 12, // Dutch 'januari' => 1, 'februari' => 2, 'maart' => 3, 'april' => 4, 'mei' => 5, 'juni' => 6, 'juli' => 7, 'augustus' => 8, 'september' => 9, 'oktober' => 10, 'november' => 11, 'december' => 12, // French 'janvier' => 1, 'février' => 2, 'mars' => 3, 'avril' => 4, 'mai' => 5, 'juin' => 6, 'juillet' => 7, 'août' => 8, 'septembre' => 9, 'octobre' => 10, 'novembre' => 11, 'décembre' => 12, // German 'januar' => 1, 'jan' => 1, 'februar' => 2, 'feb' => 2, 'märz' => 3, 'mär' => 3, 'april' => 4, 'apr' => 4, 'mai' => 5, // no short form for may 'juni' => 6, 'jun' => 6, 'juli' => 7, 'jul' => 7, 'august' => 8, 'aug' => 8, 'september' => 9, 'sep' => 9, 'oktober' => 10, 'okt' => 10, 'november' => 11, 'nov' => 11, 'dezember' => 12, 'dez' => 12, // Italian 'gennaio' => 1, 'febbraio' => 2, 'marzo' => 3, 'aprile' => 4, 'maggio' => 5, 'giugno' => 6, 'luglio' => 7, 'agosto' => 8, 'settembre' => 9, 'ottobre' => 10, 'novembre' => 11, 'dicembre' => 12, // Spanish 'enero' => 1, 'febrero' => 2, 'marzo' => 3, 'abril' => 4, 'mayo' => 5, 'junio' => 6, 'julio' => 7, 'agosto' => 8, 'septiembre' => 9, 'setiembre' => 9, 'octubre' => 10, 'noviembre' => 11, 'diciembre' => 12, // Finnish 'tammikuu' => 1, 'helmikuu' => 2, 'maaliskuu' => 3, 'huhtikuu' => 4, 'toukokuu' => 5, 'kesäkuu' => 6, 'heinäkuu' => 7, 'elokuu' => 8, 'suuskuu' => 9, 'lokakuu' => 10, 'marras' => 11, 'joulukuu' => 12, // Hungarian 'január' => 1, 'február' => 2, 'március' => 3, 'április' => 4, 'május' => 5, 'június' => 6, 'július' => 7, 'augusztus' => 8, 'szeptember' => 9, 'október' => 10, 'november' => 11, 'december' => 12, // Greek 'Ιαν' => 1, 'Φεβ' => 2, 'Μάώ' => 3, 'Μαώ' => 3, 'Απρ' => 4, 'Μάι' => 5, 'Μαϊ' => 5, 'Μαι' => 5, 'Ιούν' => 6, 'Ιον' => 6, 'Ιούλ' => 7, 'Ιολ' => 7, 'Αύγ' => 8, 'Αυγ' => 8, 'Σεπ' => 9, 'Οκτ' => 10, 'Νοέ' => 11, 'Δεκ' => 12, // Russian 'Янв' => 1, 'января' => 1, 'Фев' => 2, 'февраля' => 2, 'Мар' => 3, 'марта' => 3, 'Апр' => 4, 'апреля' => 4, 'Май' => 5, 'мая' => 5, 'Июн' => 6, 'июня' => 6, 'Июл' => 7, 'июля' => 7, 'Авг' => 8, 'августа' => 8, 'Сен' => 9, 'сентября' => 9, 'Окт' => 10, 'октября' => 10, 'Ноя' => 11, 'ноября' => 11, 'Дек' => 12, 'декабря' => 12, ); /** * List of timezones, abbreviation => offset from UTC * * @access protected * @var array */ var $timezone = array( 'ACDT' => 37800, 'ACIT' => 28800, 'ACST' => 34200, 'ACT' => -18000, 'ACWDT' => 35100, 'ACWST' => 31500, 'AEDT' => 39600, 'AEST' => 36000, 'AFT' => 16200, 'AKDT' => -28800, 'AKST' => -32400, 'AMDT' => 18000, 'AMT' => -14400, 'ANAST' => 46800, 'ANAT' => 43200, 'ART' => -10800, 'AZOST' => -3600, 'AZST' => 18000, 'AZT' => 14400, 'BIOT' => 21600, 'BIT' => -43200, 'BOT' => -14400, 'BRST' => -7200, 'BRT' => -10800, 'BST' => 3600, 'BTT' => 21600, 'CAST' => 18000, 'CAT' => 7200, 'CCT' => 23400, 'CDT' => -18000, 'CEDT' => 7200, 'CEST' => 7200, 'CET' => 3600, 'CGST' => -7200, 'CGT' => -10800, 'CHADT' => 49500, 'CHAST' => 45900, 'CIST' => -28800, 'CKT' => -36000, 'CLDT' => -10800, 'CLST' => -14400, 'COT' => -18000, 'CST' => -21600, 'CVT' => -3600, 'CXT' => 25200, 'DAVT' => 25200, 'DTAT' => 36000, 'EADT' => -18000, 'EAST' => -21600, 'EAT' => 10800, 'ECT' => -18000, 'EDT' => -14400, 'EEST' => 10800, 'EET' => 7200, 'EGT' => -3600, 'EKST' => 21600, 'EST' => -18000, 'FJT' => 43200, 'FKDT' => -10800, 'FKST' => -14400, 'FNT' => -7200, 'GALT' => -21600, 'GEDT' => 14400, 'GEST' => 10800, 'GFT' => -10800, 'GILT' => 43200, 'GIT' => -32400, 'GST' => 14400, 'GST' => -7200, 'GYT' => -14400, 'HAA' => -10800, 'HAC' => -18000, 'HADT' => -32400, 'HAE' => -14400, 'HAP' => -25200, 'HAR' => -21600, 'HAST' => -36000, 'HAT' => -9000, 'HAY' => -28800, 'HKST' => 28800, 'HMT' => 18000, 'HNA' => -14400, 'HNC' => -21600, 'HNE' => -18000, 'HNP' => -28800, 'HNR' => -25200, 'HNT' => -12600, 'HNY' => -32400, 'IRDT' => 16200, 'IRKST' => 32400, 'IRKT' => 28800, 'IRST' => 12600, 'JFDT' => -10800, 'JFST' => -14400, 'JST' => 32400, 'KGST' => 21600, 'KGT' => 18000, 'KOST' => 39600, 'KOVST' => 28800, 'KOVT' => 25200, 'KRAST' => 28800, 'KRAT' => 25200, 'KST' => 32400, 'LHDT' => 39600, 'LHST' => 37800, 'LINT' => 50400, 'LKT' => 21600, 'MAGST' => 43200, 'MAGT' => 39600, 'MAWT' => 21600, 'MDT' => -21600, 'MESZ' => 7200, 'MEZ' => 3600, 'MHT' => 43200, 'MIT' => -34200, 'MNST' => 32400, 'MSDT' => 14400, 'MSST' => 10800, 'MST' => -25200, 'MUT' => 14400, 'MVT' => 18000, 'MYT' => 28800, 'NCT' => 39600, 'NDT' => -9000, 'NFT' => 41400, 'NMIT' => 36000, 'NOVST' => 25200, 'NOVT' => 21600, 'NPT' => 20700, 'NRT' => 43200, 'NST' => -12600, 'NUT' => -39600, 'NZDT' => 46800, 'NZST' => 43200, 'OMSST' => 25200, 'OMST' => 21600, 'PDT' => -25200, 'PET' => -18000, 'PETST' => 46800, 'PETT' => 43200, 'PGT' => 36000, 'PHOT' => 46800, 'PHT' => 28800, 'PKT' => 18000, 'PMDT' => -7200, 'PMST' => -10800, 'PONT' => 39600, 'PST' => -28800, 'PWT' => 32400, 'PYST' => -10800, 'PYT' => -14400, 'RET' => 14400, 'ROTT' => -10800, 'SAMST' => 18000, 'SAMT' => 14400, 'SAST' => 7200, 'SBT' => 39600, 'SCDT' => 46800, 'SCST' => 43200, 'SCT' => 14400, 'SEST' => 3600, 'SGT' => 28800, 'SIT' => 28800, 'SRT' => -10800, 'SST' => -39600, 'SYST' => 10800, 'SYT' => 7200, 'TFT' => 18000, 'THAT' => -36000, 'TJT' => 18000, 'TKT' => -36000, 'TMT' => 18000, 'TOT' => 46800, 'TPT' => 32400, 'TRUT' => 36000, 'TVT' => 43200, 'TWT' => 28800, 'UYST' => -7200, 'UYT' => -10800, 'UZT' => 18000, 'VET' => -14400, 'VLAST' => 39600, 'VLAT' => 36000, 'VOST' => 21600, 'VUT' => 39600, 'WAST' => 7200, 'WAT' => 3600, 'WDT' => 32400, 'WEST' => 3600, 'WFT' => 43200, 'WIB' => 25200, 'WIT' => 32400, 'WITA' => 28800, 'WKST' => 18000, 'WST' => 28800, 'YAKST' => 36000, 'YAKT' => 32400, 'YAPT' => 36000, 'YEKST' => 21600, 'YEKT' => 18000, ); /** * Cached PCRE for SimplePie_Parse_Date::$day * * @access protected * @var string */ var $day_pcre; /** * Cached PCRE for SimplePie_Parse_Date::$month * * @access protected * @var string */ var $month_pcre; /** * Array of user-added callback methods * * @access private * @var array */ var $built_in = array(); /** * Array of user-added callback methods * * @access private * @var array */ var $user = array(); /** * Create new SimplePie_Parse_Date object, and set self::day_pcre, * self::month_pcre, and self::built_in * * @access private */ public function __construct() { $this->day_pcre = '(' . implode('|', array_keys($this->day)) . ')'; $this->month_pcre = '(' . implode('|', array_keys($this->month)) . ')'; static $cache; if (!isset($cache[get_class($this)])) { $all_methods = get_class_methods($this); foreach ($all_methods as $method) { if (strtolower(substr($method, 0, 5)) === 'date_') { $cache[get_class($this)][] = $method; } } } foreach ($cache[get_class($this)] as $method) { $this->built_in[] = $method; } } /** * Get the object * * @access public */ public static function get() { static $object; if (!$object) { $object = new SimplePie_Parse_Date; } return $object; } /** * Parse a date * * @final * @access public * @param string $date Date to parse * @return int Timestamp corresponding to date string, or false on failure */ public function parse($date) { foreach ($this->user as $method) { if (($returned = call_user_func($method, $date)) !== false) { return $returned; } } foreach ($this->built_in as $method) { if (($returned = call_user_func(array($this, $method), $date)) !== false) { return $returned; } } return false; } /** * Add a callback method to parse a date * * @final * @access public * @param callback $callback */ public function add_callback($callback) { if (is_callable($callback)) { $this->user[] = $callback; } else { trigger_error('User-supplied function must be a valid callback', E_USER_WARNING); } } /** * Parse a superset of W3C-DTF (allows hyphens and colons to be omitted, as * well as allowing any of upper or lower case "T", horizontal tabs, or * spaces to be used as the time separator (including more than one)) * * @access protected * @return int Timestamp */ public function date_w3cdtf($date) { static $pcre; if (!$pcre) { $year = '([0-9]{4})'; $month = $day = $hour = $minute = $second = '([0-9]{2})'; $decimal = '([0-9]*)'; $zone = '(?:(Z)|([+\-])([0-9]{1,2}):?([0-9]{1,2}))'; $pcre = '/^' . $year . '(?:-?' . $month . '(?:-?' . $day . '(?:[Tt\x09\x20]+' . $hour . '(?::?' . $minute . '(?::?' . $second . '(?:.' . $decimal . ')?)?)?' . $zone . ')?)?)?$/'; } if (preg_match($pcre, $date, $match)) { /* Capturing subpatterns: 1: Year 2: Month 3: Day 4: Hour 5: Minute 6: Second 7: Decimal fraction of a second 8: Zulu 9: Timezone ± 10: Timezone hours 11: Timezone minutes */ // Fill in empty matches for ($i = count($match); $i <= 3; $i++) { $match[$i] = '1'; } for ($i = count($match); $i <= 7; $i++) { $match[$i] = '0'; } // Numeric timezone if (isset($match[9]) && $match[9] !== '') { $timezone = $match[10] * 3600; $timezone += $match[11] * 60; if ($match[9] === '-') { $timezone = 0 - $timezone; } } else { $timezone = 0; } // Convert the number of seconds to an integer, taking decimals into account $second = round((int)$match[6] + (int)$match[7] / (10 ** strlen($match[7]))); return gmmktime($match[4], $match[5], $second, $match[2], $match[3], $match[1]) - $timezone; } return false; } /** * Remove RFC822 comments * * @access protected * @param string $data Data to strip comments from * @return string Comment stripped string */ public function remove_rfc2822_comments($string) { $string = (string) $string; $position = 0; $length = strlen($string); $depth = 0; $output = ''; while ($position < $length && ($pos = strpos($string, '(', $position)) !== false) { $output .= substr($string, $position, $pos - $position); $position = $pos + 1; if ($pos === 0 || $string[$pos - 1] !== '\\') { $depth++; while ($depth && $position < $length) { $position += strcspn($string, '()', $position); if ($string[$position - 1] === '\\') { $position++; continue; } elseif (isset($string[$position])) { switch ($string[$position]) { case '(': $depth++; break; case ')': $depth--; break; } $position++; } else { break; } } } else { $output .= '('; } } $output .= substr($string, $position); return $output; } /** * Parse RFC2822's date format * * @access protected * @return int Timestamp */ public function date_rfc2822($date) { static $pcre; if (!$pcre) { $wsp = '[\x09\x20]'; $fws = '(?:' . $wsp . '+|' . $wsp . '*(?:\x0D\x0A' . $wsp . '+)+)'; $optional_fws = $fws . '?'; $day_name = $this->day_pcre; $month = $this->month_pcre; $day = '([0-9]{1,2})'; $hour = $minute = $second = '([0-9]{2})'; $year = '([0-9]{2,4})'; $num_zone = '([+\-])([0-9]{2})([0-9]{2})'; $character_zone = '([A-Z]{1,5})'; $zone = '(?:' . $num_zone . '|' . $character_zone . ')'; $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'; } if (preg_match($pcre, $this->remove_rfc2822_comments($date), $match)) { /* Capturing subpatterns: 1: Day name 2: Day 3: Month 4: Year 5: Hour 6: Minute 7: Second 8: Timezone ± 9: Timezone hours 10: Timezone minutes 11: Alphabetic timezone */ // Find the month number $month = $this->month[strtolower($match[3])]; // Numeric timezone if ($match[8] !== '') { $timezone = $match[9] * 3600; $timezone += $match[10] * 60; if ($match[8] === '-') { $timezone = 0 - $timezone; } } // Character timezone elseif (isset($this->timezone[strtoupper($match[11])])) { $timezone = $this->timezone[strtoupper($match[11])]; } // Assume everything else to be -0000 else { $timezone = 0; } // Deal with 2/3 digit years if ($match[4] < 50) { $match[4] += 2000; } elseif ($match[4] < 1000) { $match[4] += 1900; } // Second is optional, if it is empty set it to zero if ($match[7] !== '') { $second = $match[7]; } else { $second = 0; } return gmmktime($match[5], $match[6], $second, $month, $match[2], $match[4]) - $timezone; } return false; } /** * Parse RFC850's date format * * @access protected * @return int Timestamp */ public function date_rfc850($date) { static $pcre; if (!$pcre) { $space = '[\x09\x20]+'; $day_name = $this->day_pcre; $month = $this->month_pcre; $day = '([0-9]{1,2})'; $year = $hour = $minute = $second = '([0-9]{2})'; $zone = '([A-Z]{1,5})'; $pcre = '/^' . $day_name . ',' . $space . $day . '-' . $month . '-' . $year . $space . $hour . ':' . $minute . ':' . $second . $space . $zone . '$/i'; } if (preg_match($pcre, $date, $match)) { /* Capturing subpatterns: 1: Day name 2: Day 3: Month 4: Year 5: Hour 6: Minute 7: Second 8: Timezone */ // Month $month = $this->month[strtolower($match[3])]; // Character timezone if (isset($this->timezone[strtoupper($match[8])])) { $timezone = $this->timezone[strtoupper($match[8])]; } // Assume everything else to be -0000 else { $timezone = 0; } // Deal with 2 digit year if ($match[4] < 50) { $match[4] += 2000; } else { $match[4] += 1900; } return gmmktime($match[5], $match[6], $match[7], $month, $match[2], $match[4]) - $timezone; } return false; } /** * Parse C99's asctime()'s date format * * @access protected * @return int Timestamp */ public function date_asctime($date) { static $pcre; if (!$pcre) { $space = '[\x09\x20]+'; $wday_name = $this->day_pcre; $mon_name = $this->month_pcre; $day = '([0-9]{1,2})'; $hour = $sec = $min = '([0-9]{2})'; $year = '([0-9]{4})'; $terminator = '\x0A?\x00?'; $pcre = '/^' . $wday_name . $space . $mon_name . $space . $day . $space . $hour . ':' . $min . ':' . $sec . $space . $year . $terminator . '$/i'; } if (preg_match($pcre, $date, $match)) { /* Capturing subpatterns: 1: Day name 2: Month 3: Day 4: Hour 5: Minute 6: Second 7: Year */ $month = $this->month[strtolower($match[2])]; return gmmktime($match[4], $match[5], $match[6], $month, $match[3], $match[7]); } return false; } /** * Parse dates using strtotime() * * @access protected * @return int Timestamp */ public function date_strtotime($date) { $strtotime = strtotime($date); if ($strtotime === -1 || $strtotime === false) { return false; } return $strtotime; } }