Neos\Flow\I18n\Parser\DatetimeParser::doParsingInLenientMode PHP Метод

doParsingInLenientMode() защищенный Метод

Algorithm assumptions: - ignore all literals - order of elements in parsed format is important - length of subformat is not strictly checked (eg. 'h' and 'hh') - number must be in range in order to be accepted (eg. 1-12 for month) - some format fallback substitutions can be done (eg. 'Jan' for 'January')
См. также: DatesReader
protected doParsingInLenientMode ( string $datetimeToParse, array $parsedFormat, array $localizedLiterals ) : array
$datetimeToParse string Date/time to be parsed
$parsedFormat array Format parsed by DatesReader
$localizedLiterals array Array of date / time literals from CLDR
Результат array Array of parsed date and / or time elements (can be array of NULLs if nothing was parsed)
    protected function doParsingInLenientMode($datetimeToParse, array $parsedFormat, array $localizedLiterals)
    {
        $datetimeElements = ['year' => null, 'month' => null, 'day' => null, 'hour' => null, 'minute' => null, 'second' => null, 'timezone' => null];
        $using12HourClock = false;
        $timeIsPm = false;
        foreach ($parsedFormat as $subformat) {
            try {
                if (is_array($subformat)) {
                    // This is literal string, and we ignore them
                    continue;
                }
                $lengthOfSubformat = strlen($subformat);
                $numberOfCharactersToRemove = 0;
                $position = 0;
                switch ($subformat[0]) {
                    case 'K':
                        $hour = $this->extractNumberAndGetPosition($datetimeToParse, $position);
                        if ($hour >= 0 && $hour <= 11) {
                            $numberOfCharactersToRemove = $position + strlen($hour);
                            $datetimeElements['hour'] = (int) $hour;
                            $using12HourClock = true;
                            break;
                        }
                    case 'h':
                        if (!isset($hour)) {
                            $hour = $this->extractNumberAndGetPosition($datetimeToParse, $position);
                        }
                        if ($hour >= 1 && $hour <= 12) {
                            $numberOfCharactersToRemove = $position + strlen($hour);
                            if ((int) $hour === 12) {
                                $hour = 0;
                            }
                            $datetimeElements['hour'] = (int) $hour;
                            $using12HourClock = true;
                            break;
                        }
                    case 'H':
                        if (!isset($hour)) {
                            $hour = $this->extractNumberAndGetPosition($datetimeToParse, $position);
                        }
                        if ($hour >= 0 && $hour <= 23) {
                            $numberOfCharactersToRemove = $position + strlen($hour);
                            $datetimeElements['hour'] = (int) $hour;
                            break;
                        }
                    case 'k':
                        if (!isset($hour)) {
                            $hour = $this->extractNumberAndGetPosition($datetimeToParse, $position);
                        }
                        if ($hour >= 1 && $hour <= 24) {
                            $numberOfCharactersToRemove = $position + strlen($hour);
                            if ((int) $hour === 24) {
                                $hour = 0;
                            }
                            $datetimeElements['hour'] = (int) $hour;
                            break;
                        } else {
                            throw new Exception\InvalidParseStringException('Unable to match number string to any hour format.', 1280488645);
                        }
                    case 'a':
                        $dayPeriods = $localizedLiterals['dayPeriods']['format']['wide'];
                        $positionOfDayPeriod = strpos($datetimeToParse, $dayPeriods['am']);
                        if ($positionOfDayPeriod !== false) {
                            $numberOfCharactersToRemove = $positionOfDayPeriod + strlen($dayPeriods['am']);
                        } else {
                            $positionOfDayPeriod = strpos($datetimeToParse, $dayPeriods['pm']);
                            if ($positionOfDayPeriod !== false) {
                                $numberOfCharactersToRemove = $positionOfDayPeriod + strlen($dayPeriods['pm']);
                                $timeIsPm = true;
                            } else {
                                throw new Exception\InvalidParseStringException('Unable to match any day period.', 1280489183);
                            }
                        }
                        break;
                    case 'm':
                        $minute = $this->extractNumberAndGetPosition($datetimeToParse, $position);
                        if ($minute < 0 && $minute > 59) {
                            throw new Exception\InvalidParseStringException('Expected minute is out of range.', 1280489411);
                        }
                        $numberOfCharactersToRemove = $position + strlen($minute);
                        $datetimeElements['minute'] = (int) $minute;
                        break;
                    case 's':
                        $second = $this->extractNumberAndGetPosition($datetimeToParse, $position);
                        if ($second < 0 && $second > 59) {
                            throw new Exception\InvalidParseStringException('Expected second is out of range.', 1280489412);
                        }
                        $numberOfCharactersToRemove = $position + strlen($second);
                        $datetimeElements['second'] = (int) $second;
                        break;
                    case 'd':
                        $day = $this->extractNumberAndGetPosition($datetimeToParse, $position);
                        if ($day < 1 && $day > 31) {
                            throw new Exception\InvalidParseStringException('Expected day is out of range.', 1280489413);
                        }
                        $numberOfCharactersToRemove = $position + strlen($day);
                        $datetimeElements['day'] = (int) $day;
                        break;
                    case 'M':
                    case 'L':
                        $typeOfLiteral = $subformat[0] === 'L' ? 'stand-alone' : 'format';
                        switch ($lengthOfSubformat) {
                            case 1:
                            case 2:
                                try {
                                    $month = $this->extractNumberAndGetPosition($datetimeToParse, $position);
                                    if ($month >= 1 && $month <= 31) {
                                        $numberOfCharactersToRemove = $position + strlen($month);
                                        $datetimeElements['month'] = (int) $month;
                                        break;
                                    }
                                } catch (Exception\InvalidParseStringException $exception) {
                                    // Try to match month's name by cases below
                                }
                            case 3:
                                foreach ($localizedLiterals['months'][$typeOfLiteral]['abbreviated'] as $monthId => $monthName) {
                                    $positionOfMonthName = strpos($datetimeToParse, $monthName);
                                    if ($positionOfMonthName !== false) {
                                        $numberOfCharactersToRemove = $positionOfMonthName + strlen($monthName);
                                        $datetimeElements['month'] = (int) $monthId;
                                        break;
                                    }
                                }
                                if ($datetimeElements['month'] !== null) {
                                    break;
                                }
                            case 4:
                                foreach ($localizedLiterals['months'][$typeOfLiteral]['wide'] as $monthId => $monthName) {
                                    $positionOfMonthName = strpos($datetimeToParse, $monthName);
                                    if ($positionOfMonthName !== false) {
                                        $numberOfCharactersToRemove = $positionOfMonthName + strlen($monthName);
                                        $datetimeElements['month'] = (int) $monthId;
                                        break;
                                    }
                                }
                                if ($datetimeElements['month'] === null) {
                                    throw new Exception\InvalidParseStringException('Neither month name or number were matched.', 1280497950);
                                }
                            default:
                                throw new InvalidArgumentException('Cannot parse formats with narrow month pattern as it is not unique.', 1280495827);
                        }
                        break;
                    case 'y':
                        $year = $this->extractNumberAndGetPosition($datetimeToParse, $position);
                        $numberOfCharactersToRemove = $position + strlen($year);
                        /** @todo Two digits date (like 99) shoud be handled here somehow **/
                        $datetimeElements['year'] = (int) $year;
                        break;
                    case 'v':
                    case 'z':
                        if ($lengthOfSubformat <= 3) {
                            $firstPattern = self::PATTERN_MATCH_LENIENT_TIMEZONE_ABBREVIATION;
                            $secondPattern = self::PATTERN_MATCH_LENIENT_TIMEZONE_TZ;
                        } else {
                            $firstPattern = self::PATTERN_MATCH_LENIENT_TIMEZONE_TZ;
                            $secondPattern = self::PATTERN_MATCH_LENIENT_TIMEZONE_ABBREVIATION;
                        }
                        if (preg_match($firstPattern, $datetimeToParse, $matches) === 0) {
                            if (preg_match($secondPattern, $datetimeToParse, $matches) === 0) {
                                throw new Exception\InvalidParseStringException('Expected timezone identifier was not found.', 1280492312);
                            }
                        }
                        $timezone = $matches[0];
                        $numberOfCharactersToRemove = strpos($datetimeToParse, $timezone) + strlen($timezone);
                        $datetimeElements['timezone'] = $matches[0];
                        break;
                    case 'D':
                    case 'F':
                    case 'w':
                    case 'W':
                    case 'Q':
                    case 'q':
                    case 'G':
                    case 'S':
                    case 'E':
                    case 'Y':
                    case 'u':
                    case 'l':
                    case 'g':
                    case 'e':
                    case 'c':
                    case 'A':
                    case 'Z':
                    case 'V':
                        // Silently ignore unsupported formats or formats that there is no need to parse
                        break;
                    default:
                        throw new InvalidArgumentException('Unexpected format symbol, "' . $subformat[0] . '" detected for date / time parsing.', 1279965529);
                }
                if ($using12HourClock && $timeIsPm) {
                    $datetimeElements['hour'] += 12;
                    $timeIsPm = false;
                }
                if ($numberOfCharactersToRemove > 0) {
                    $datetimeToParse = substr_replace($datetimeToParse, '', 0, $numberOfCharactersToRemove);
                }
            } catch (Exception\InvalidParseStringException $exception) {
                // Matching failed, but in lenient mode we ignore it and try to match next element
                continue;
            }
        }
        return $datetimeElements;
    }