/** * @dataProvider timezoneProvider */ public function testIsValidAndIsMilitary($abbrevation, $isValid, $isMilitary) { $this->assertEquals($isValid, Timezone::isValid($abbrevation)); $this->assertEquals($isMilitary, Timezone::isMilitary($abbrevation)); }
/** * Parse the given string to check if it a date/time value. * The function sets the provided call-by-ref values to the respective * values. If errors are encountered, they are added to the objects * error list and false is returned. Otherwise, true is returned. * @param $string string input time representation, e.g. "12 May 2007 13:45:23-3:30" * @param $datecomponents array of strings that might belong to the specification of a date * @param $calendarmodesl string if model was set in input, otherwise false * @param $era string '+' or '-' if provided, otherwise false * @param $hours integer set to a value between 0 and 24 * @param $minutes integer set to a value between 0 and 59 * @param $seconds integer set to a value between 0 and 59, or false if not given * @param $timeoffset double set to a value for time offset (e.g. 3.5), or false if not given * @return boolean stating if the parsing succeeded * @todo This method in principle allows date parsing to be internationalized further. Should be done. */ protected function parseDateString($string, &$datecomponents, &$calendarmodel, &$era, &$hours, &$minutes, &$seconds, &$microseconds, &$timeoffset, &$timezone) { $calendarmodel = $timezoneoffset = $era = $ampm = false; $hours = $minutes = $seconds = $microseconds = $timeoffset = $timezone = false; // Fetch possible "America/Argentina/Mendoza" $timzoneIdentifier = substr($string, strrpos($string, ' ') + 1); if (Timezone::isValid($timzoneIdentifier)) { $string = str_replace($timzoneIdentifier, '', $string); $timezoneoffset = Timezone::getOffsetByAbbreviation($timzoneIdentifier) / 3600; $timezone = Timezone::getIdByAbbreviation($timzoneIdentifier); } // crude preprocessing for supporting different date separation characters; // * this does not allow localized time notations such as "10.34 pm" // * this creates problems with keywords that contain "." such as "p.m." // * yet "." is an essential date separation character in languages such as German $parsevalue = str_replace(array('/', '.', ' ', ',', '年', '月', '日', '時', '分'), array('-', ' ', ' ', ' ', ' ', ' ', ' ', ':', ' '), $string); $matches = preg_split("/([T]?[0-2]?[0-9]:[\\:0-9]+[+\\-]?[0-2]?[0-9\\:]+|[\\p{L}]+|[0-9]+|[ ])/u", $parsevalue, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); $datecomponents = array(); $unclearparts = array(); $matchisnumber = false; // used for looking back; numbers are days/months/years by default but may be re-interpreted if certain further symbols are found $matchisdate = false; // used for ensuring that date parts are in one block foreach ($matches as $match) { $prevmatchwasnumber = $matchisnumber; $prevmatchwasdate = $matchisdate; $matchisnumber = $matchisdate = false; if ($match == ' ') { $matchisdate = $prevmatchwasdate; // spaces in dates do not end the date } elseif ($match == '-') { // can only occur separately between date components $datecomponents[] = $match; // we check later if this makes sense $matchisdate = true; } elseif (is_numeric($match) && ($prevmatchwasdate || count($datecomponents) == 0)) { $datecomponents[] = $match; $matchisnumber = true; $matchisdate = true; } elseif ($era === false && in_array($match, array('AD', 'CE'))) { $era = '+'; } elseif ($era === false && in_array($match, array('BC', 'BCE'))) { $era = '-'; } elseif ($calendarmodel === false && in_array($match, array('Gr', 'GR', 'He', 'Jl', 'JL', 'MJD', 'JD', 'OS'))) { $calendarmodel = $match; } elseif ($ampm === false && (strtolower($match) === 'am' || strtolower($match) === 'pm')) { $ampm = strtolower($match); } elseif ($hours === false && self::parseTimeString($match, $hours, $minutes, $seconds, $timeoffset)) { // nothing to do } elseif ($hours !== false && $timezoneoffset === false && Timezone::isValid($match)) { // only accept timezone if time has already been set $timezoneoffset = Timezone::getOffsetByAbbreviation($match) / 3600; $timezone = Timezone::getIdByAbbreviation($match); } elseif ($prevmatchwasnumber && $hours === false && $timezoneoffset === false && Timezone::isMilitary($match) && self::parseMilTimeString(end($datecomponents), $hours, $minutes, $seconds)) { // military timezone notation is found after a number -> re-interpret the number as military time array_pop($datecomponents); $timezoneoffset = Timezone::getOffsetByAbbreviation($match) / 3600; $timezone = Timezone::getIdByAbbreviation($match); } elseif (($prevmatchwasdate || count($datecomponents) == 0) && $this->parseMonthString($match, $monthname)) { $datecomponents[] = $monthname; $matchisdate = true; } elseif ($prevmatchwasnumber && $prevmatchwasdate && in_array($match, array('st', 'nd', 'rd', 'th'))) { $datecomponents[] = 'd' . strval(array_pop($datecomponents)); // must be a day; add standard marker $matchisdate = true; } elseif (count($match) == 1) { $microseconds = $match; } else { $unclearparts[] = $match; } } // Useful for debugging: // print "\n\n Results \n\n"; // debug_zval_dump( $datecomponents ); // print "\ncalendarmodel: $calendarmodel \ntimezoneoffset: $timezoneoffset \nera: $era \nampm: $ampm \nh: $hours \nm: $minutes \ns:$seconds \ntimeoffset: $timeoffset \n"; // debug_zval_dump( $unclearparts ); // Abort if we found unclear or over-specific information: if (count($unclearparts) != 0) { $this->addErrorMsg(array('smw-datavalue-time-invalid-values', $this->m_wikivalue, implode(', ', $unclearparts))); return false; } if ($timezoneoffset !== false && $timeoffset !== false) { $this->addErrorMsg(array('smw-datavalue-time-invalid-offset-zone-usage', $this->m_wikivalue)); return false; } if ($timezoneoffset !== false && $timeoffset !== false) { $this->addErrorMsg(array('smw-datavalue-time-invalid-offset-zone-usage', $this->m_wikivalue)); return false; } $timeoffset = $timeoffset + $timezoneoffset; // Check if the a.m. and p.m. information is meaningful if ($ampm !== false && ($hours > 12 || $hours == 0)) { // Note: the == 0 check subsumes $hours===false $this->addErrorMsg(array('smw-datavalue-time-invalid-ampm', $this->m_wikivalue, $hours)); return false; } elseif ($ampm == 'am' && $hours == 12) { $hours = 0; } elseif ($ampm == 'pm' && $hours < 12) { $hours += 12; } return true; }