PHP date_parse_from_format () альтернатива в PHP 5.2

Поскольку date_parse_from_format () доступен только в PHP 5.3, мне нужно написать функцию, которая имитирует ее поведение в PHP 5.2.

Можно ли написать эту функцию для PHP 5.2 и заставить ее работать точно так же, как в PHP 5.3?

Пример:

Для этого входа:

<?php $date = "6.1.2009 13:00+01:00"; print_r(date_parse_from_format("jnY H:iP", $date)); ?> 

Мне нужен этот вывод:

 Array ( [year] => 2009 [month] => 1 [day] => 6 [hour] => 13 [minute] => 0 [second] => 0 [fraction] => [warning_count] => 0 [warnings] => Array ( ) [error_count] => 0 [errors] => Array ( ) [is_localtime] => 1 [zone_type] => 1 [zone] => -60 [is_dst] => ) 

 <?php function date_parse_from_format($format, $date) { $dMask = array( 'H'=>'hour', 'i'=>'minute', 's'=>'second', 'y'=>'year', 'm'=>'month', 'd'=>'day' ); $format = preg_split('//', $format, -1, PREG_SPLIT_NO_EMPTY); $date = preg_split('//', $date, -1, PREG_SPLIT_NO_EMPTY); foreach ($date as $k => $v) { if ($dMask[$format[$k]]) $dt[$dMask[$format[$k]]] .= $v; } return $dt; } ?> 

Пример 1:

 <?php print_r(date_parse_from_format('mmddyyyy','03232011'); ?> 

Выход 1:

Массив ([месяц] => 03 [день] => 23 [год] => 2011)

Пример 2:

  <?php print_r(date_parse_from_format('yyyy.mm.dd HH:ii:ss','2011.03.23 12:03:00')); ?> 

Выход 2:

Массив ([год] => 2011 [месяц] => 03 [день] => 23 [час] => 12 [минута] => 03 [секунда] => 00)

Вот моя улучшенная версия, и я думаю, что она завершена. Только ошибки и предупреждения не принимаются во внимание.

 if( !function_exists('date_parse_from_format') ){ function date_parse_from_format($format, $date) { // reverse engineer date formats $keys = array( 'Y' => array('year', '\d{4}'), //Année sur 4 chiffres 'y' => array('year', '\d{2}'), //Année sur 2 chiffres 'm' => array('month', '\d{2}'), //Mois au format numérique, avec zéros initiaux 'n' => array('month', '\d{1,2}'), //Mois sans les zéros initiaux 'M' => array('month', '[AZ][az]{3}'), //Mois, en trois lettres, en anglais 'F' => array('month', '[AZ][az]{2,8}'), //Mois, textuel, version longue; en anglais, comme January ou December 'd' => array('day', '\d{2}'), //Jour du mois, sur deux chiffres (avec un zéro initial) 'j' => array('day', '\d{1,2}'), //Jour du mois sans les zéros initiaux 'D' => array('day', '[AZ][az]{2}'), //Jour de la semaine, en trois lettres (et en anglais) 'l' => array('day', '[AZ][az]{6,9}'), //Jour de la semaine, textuel, version longue, en anglais 'u' => array('hour', '\d{1,6}'), //Microsecondes 'h' => array('hour', '\d{2}'), //Heure, au format 12h, avec les zéros initiaux 'H' => array('hour', '\d{2}'), //Heure, au format 24h, avec les zéros initiaux 'g' => array('hour', '\d{1,2}'), //Heure, au format 12h, sans les zéros initiaux 'G' => array('hour', '\d{1,2}'), //Heure, au format 24h, sans les zéros initiaux 'i' => array('minute', '\d{2}'), //Minutes avec les zéros initiaux 's' => array('second', '\d{2}') //Secondes, avec zéros initiaux ); // convert format string to regex $regex = ''; $chars = str_split($format); foreach ( $chars AS $n => $char ) { $lastChar = isset($chars[$n-1]) ? $chars[$n-1] : ''; $skipCurrent = '\\' == $lastChar; if ( !$skipCurrent && isset($keys[$char]) ) { $regex .= '(?P<'.$keys[$char][0].'>'.$keys[$char][1].')'; } else if ( '\\' == $char ) { $regex .= $char; } else { $regex .= preg_quote($char); } } $dt = array(); // now try to match it if( preg_match('#^'.$regex.'$#', $date, $dt) ){ foreach ( $dt AS $k => $v ){ if ( is_int($k) ){ unset($dt[$k]); } } if( !checkdate($dt['month'], $dt['day'], $dt['year']) ){ $dt['error_count'] = 1; } else { $dt['error_count'] = 0; } } else { $dt['error_count'] = 1; } $dt['errors'] = array(); $dt['fraction'] = ''; $dt['warning_count'] = 0; $dt['warnings'] = array(); $dt['is_localtime'] = 0; $dt['zone_type'] = 0; $dt['zone'] = 0; $dt['is_dst'] = ''; return $dt; } } с if( !function_exists('date_parse_from_format') ){ function date_parse_from_format($format, $date) { // reverse engineer date formats $keys = array( 'Y' => array('year', '\d{4}'), //Année sur 4 chiffres 'y' => array('year', '\d{2}'), //Année sur 2 chiffres 'm' => array('month', '\d{2}'), //Mois au format numérique, avec zéros initiaux 'n' => array('month', '\d{1,2}'), //Mois sans les zéros initiaux 'M' => array('month', '[AZ][az]{3}'), //Mois, en trois lettres, en anglais 'F' => array('month', '[AZ][az]{2,8}'), //Mois, textuel, version longue; en anglais, comme January ou December 'd' => array('day', '\d{2}'), //Jour du mois, sur deux chiffres (avec un zéro initial) 'j' => array('day', '\d{1,2}'), //Jour du mois sans les zéros initiaux 'D' => array('day', '[AZ][az]{2}'), //Jour de la semaine, en trois lettres (et en anglais) 'l' => array('day', '[AZ][az]{6,9}'), //Jour de la semaine, textuel, version longue, en anglais 'u' => array('hour', '\d{1,6}'), //Microsecondes 'h' => array('hour', '\d{2}'), //Heure, au format 12h, avec les zéros initiaux 'H' => array('hour', '\d{2}'), //Heure, au format 24h, avec les zéros initiaux 'g' => array('hour', '\d{1,2}'), //Heure, au format 12h, sans les zéros initiaux 'G' => array('hour', '\d{1,2}'), //Heure, au format 24h, sans les zéros initiaux 'i' => array('minute', '\d{2}'), //Minutes avec les zéros initiaux 's' => array('second', '\d{2}') //Secondes, avec zéros initiaux ); // convert format string to regex $regex = ''; $chars = str_split($format); foreach ( $chars AS $n => $char ) { $lastChar = isset($chars[$n-1]) ? $chars[$n-1] : ''; $skipCurrent = '\\' == $lastChar; if ( !$skipCurrent && isset($keys[$char]) ) { $regex .= '(?P<'.$keys[$char][0].'>'.$keys[$char][1].')'; } else if ( '\\' == $char ) { $regex .= $char; } else { $regex .= preg_quote($char); } } $dt = array(); // now try to match it if( preg_match('#^'.$regex.'$#', $date, $dt) ){ foreach ( $dt AS $k => $v ){ if ( is_int($k) ){ unset($dt[$k]); } } if( !checkdate($dt['month'], $dt['day'], $dt['year']) ){ $dt['error_count'] = 1; } else { $dt['error_count'] = 0; } } else { $dt['error_count'] = 1; } $dt['errors'] = array(); $dt['fraction'] = ''; $dt['warning_count'] = 0; $dt['warnings'] = array(); $dt['is_localtime'] = 0; $dt['zone_type'] = 0; $dt['zone'] = 0; $dt['is_dst'] = ''; return $dt; } } 

Если вы хотите, чтобы это было точно так же, как функция PHP 5.3, вам понадобится много кода. Я бы начал с чего-то вроде этого:

 $format = '\Y: Ym-d'; var_dump($format); $date = date($format); var_dump($date); // reverse engineer date formats $keys = array( 'Y' => array('year', '\d{4}'), 'm' => array('month', '\d{2}'), 'd' => array('day', '\d{2}'), 'j' => array('day', '\d{1,2}'), 'n' => array('month', '\d{1,2}'), 'M' => array('month', '[AZ][az]{2}'), 'F' => array('month', '[AZ][az]{2,8}'), 'D' => array('day', '[AZ][az]{2}'), // etc etc etc ); // convert format string to regex $regex = ''; $chars = str_split($format); foreach ( $chars AS $n => $char ) { $lastChar = isset($chars[$n-1]) ? $chars[$n-1] : ''; $skipCurrent = '\\' == $lastChar; if ( !$skipCurrent && isset($keys[$char]) ) { $regex .= '(?P<'.$keys[$char][0].'>'.$keys[$char][1].')'; } else if ( '\\' == $char ) { $regex .= $char; } else { $regex .= preg_quote($char); } } var_dump($regex); // now try to match it if ( preg_match('#^'.$regex.'$#', $date, $matches) ) { foreach ( $matches AS $k => $v ) if ( is_int($k) ) unset($matches[$k]); print_r($matches); } else { echo 'invalid date "'.$date.'" for format "'.$format.'"'."\n"; } 

Результат:

 string(9) "\Y: Ymd" string(13) "Y: 2011-07-12" string(51) "\Y\: (?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})" Array ( [year] => 2011 [month] => 07 [day] => 12 ) 

Неполный и несовершенный.

Сначала я хотел бы поблагодарить @rudie за его ответ и @jeremy уточнения его ответа.

Мне нужна была более гибкая версия, которая могла бы работать с jQueryUI Datepicker с плагином TimePicker. Я также нуждался в этом, чтобы работать с символом escape-лака \ backslash, чтобы иметь дело с нечетными форматами времени, которые вводит пользователи, например H\hi\m\i\n .

Вот мое решение, основанное на тех предыдущих ответах, которые я реализовал в своем подключаемом модуле WordPress для подключений .

Он более точно соответствует функциям date_parse_from_format() и DateTime::createFromFormat() .

Надеюсь, это поможет кому-то!

 <?php /** * Class cnDate */ class cnDate { /** * Date format characters and their name and regex structure. * * @access public * @since 8.6.4 * * @var array */ protected static $keys = array( 'Y' => array( 'year', '\d{4}' ), // Year with 4 Digits 'y' => array( 'year', '\d{2}' ), // Year with 2 Digits 'm' => array( 'month', '\d{2}' ), // Month with leading 0 'n' => array( 'month', '\d{1,2}' ), // Month without the leading 0 'M' => array( 'month', '[AZ][az]{2}' ), // Month ABBR 3 letters 'F' => array( 'month', '[AZ][az]{2,8}' ), // Month Name 'd' => array( 'day', '\d{2}' ), // Day with leading 0 'j' => array( 'day', '\d{1,2}' ), // Day without leading 0 'D' => array( 'day', '[AZ][az]{2}' ), // Day ABBR 3 Letters 'l' => array( 'day', '[AZ][az]{5,8}' ), // Day Name 'h' => array( 'hour', '\d{2}' ), // Hour 12h formatted, with leading 0 'H' => array( 'hour', '\d{2}' ), // Hour 24h formatted, with leading 0 'g' => array( 'hour', '\d{1,2}' ), // Hour 12h formatted, without leading 0 'G' => array( 'hour', '\d{1,2}' ), // Hour 24h formatted, without leading 0 'i' => array( 'minute', '\d{2}' ), // Minutes with leading 0 's' => array( 'second', '\d{2}' ), // Seconds with leading 0 'u' => array( 'hour', '\d{1,6}' ), // Microseconds 'a' => array( 'meridiem', '[ap]m' ), // Lowercase ante meridiem and Post meridiem 'A' => array( 'meridiem', '[AP]M' ), // Uppercase ante meridiem and Post meridiem ); /** * Create a regex used to parse the supplied datetime format. * * @access public * @since 8.6.4 * * @param string $format The datetime format. * * @return string */ private static function getFormatRegex( $format ) { $keys = self::$keys; // Convert format string to regex. $regex = ''; $chars = str_split( $format ); foreach ( $chars as $n => $char ) { $lastChar = isset( $chars[ $n - 1 ] ) ? $chars[ $n - 1 ] : ''; $skipCurrent = '\\' == $lastChar; if ( ! $skipCurrent && isset( $keys[ $char ] ) ) { $regex .= '(?P<' . $keys[ $char ][0] . '>' . $keys[ $char ][1] . ')'; } elseif ( '\\' == $char || '!' == $char ) { /* * No need to add the date format escaping character to the regex since it should not exist in the * supplied datetime string. Including it would cause the preg_match to fail. */ //$regex .= $char; } else { $regex .= preg_quote( $char ); } } return '#^' . $regex . '$#'; } /** * PHP 5.2 does not have a version of @see date_parse_from_format(), this is a mostly PHP 5.2 compatible version. * * @link http://stackoverflow.com/a/14196482/5351316 * * @access public * @since 8.6.4 * * @param string $format The datetime format. * @param string $date The datetime string to parse. * * @return array */ public static function parseFromFormat( $format, $date ) { /** Setup the default values to be returned, matching @see date_parse_from_format() */ $dt = array( 'year' => FALSE, 'month' => FALSE, 'day' => FALSE, 'hour' => FALSE, 'minute' => FALSE, 'second' => FALSE, 'fraction' => FALSE, 'warning_count' => 0, 'warnings' => array(), 'error_count' => 0, 'errors' => array(), 'is_localtime' => FALSE, 'zone_type' => 0, 'zone' => 0, 'is_dst' => '', ); // Now try to match it. if ( preg_match( self::getFormatRegex( $format ), $date, $matches ) ) { foreach ( $matches as $k => $v ) { // Remove unwanted indexes from resulting preg_match. if ( is_int( $k ) ) { unset( $matches[ $k ] ); } // Year, month, day, hour, minute, second and fraction should be coerced from string to int. if ( in_array( $k, array( 'year', 'month', 'day', 'hour', 'minute', 'second', 'fraction' ) ) && is_numeric( $v ) ) { $matches[ $k ] = (int) $v; } elseif ( 'month' === $k ) { $parsed = date_parse( $v ); $matches[ $k ] = (int) $parsed['month']; } elseif ( 'day' === $k ) { $parsed = date_parse( $v ); $matches[ $k ] = (int) $parsed['day']; } } } else { $dt['error_count'] = 1; $dt['errors'][] = 'Invalid date supplied.'; // @todo match error string from date_parse_from_format() } return wp_parse_args( $matches, $dt ); } /** * PHP 5.2 does not have a version of @see DateTime::createFromFormat(), this is a mostly PHP 5.2 compatible version. * * @link http://bordoni.me/date_parse_from_format-php-5-2/ * * @access public * @since 8.6.4 * * @param string $format The datetime format. * @param string $date The datetime string to parse. * * @return false|DateTime Instance of DateTime, false on failure. */ public static function createFromFormat( $format, $date ) { $keys = self::$keys; $pos = strpos( $format, '!' ); $chars = str_split( $format ); // Setup default datetime values based on time now or Unix epoch based on if `!` if present in $format. if ( FALSE !== $pos ) { $datetime = array( 'year' => '1970', 'month' => '01', 'day' => '01', 'hour' => '00', 'minute' => '00', 'second' => '00', 'fraction' => '000000', ); } else { /** @link http://stackoverflow.com/a/38334226/5351316 */ list( $usec, $sec ) = explode( ' ', microtime() ); $datetime = array( 'year' => date( 'Y', $sec ), 'month' => date( 'm', $sec ), 'day' => date( 'd', $sec ), 'hour' => date( 'H', $sec ), 'minute' => date( 'i', $sec ), 'second' => date( 's', $sec ), 'fraction' => substr( $usec, 2, 6 ), ); } $parsed = self::parseFromFormat( $format, $date ); foreach ( $chars as $n => $char ) { $lastChar = isset( $chars[ $n - 1 ] ) ? $chars[ $n - 1 ] : ''; $skipCurrent = '\\' == $lastChar; if ( ! $skipCurrent && isset( $keys[ $char ] ) ) { // Existing value exists in supplied parsed date. if ( $parsed[ $keys[ $char ][0] ] ) { /* * Replace default datetime interval with the parsed datetime interval only if * an `!` was found within the supplied $format and its position is * greater than the current $format character position. */ if ( ! ( FALSE !== $pos && $pos > $n ) ) { $datetime[ $keys[ $char ][0] ] = $parsed[ $keys[ $char ][0] ]; } } } } // Ensure the datetime integers are correctly padded with leading zeros. $datetime['month'] = str_pad( $datetime['month'], 2, '0', STR_PAD_LEFT ); $datetime['day'] = str_pad( $datetime['day'], 2, '0', STR_PAD_LEFT ); $datetime['hour'] = str_pad( $datetime['hour'], 2, '0', STR_PAD_LEFT ); $datetime['minute'] = str_pad( $datetime['minute'], 2, '0', STR_PAD_LEFT ); $datetime['second'] = str_pad( $datetime['second'], 2, '0', STR_PAD_LEFT ); // Parse the $datetime into a string which can be parsed by DateTime(). $formatted = strtr( 'year-month-day hour:minute:second.fraction', $datetime ); // Sanity check to make sure the datetime is valid. if ( ! strtotime( $formatted ) ) { return FALSE; } // Return a new DateTime instance. return new DateTime( $formatted ); } } 

Если вам не нужны последние 4 поля массива, вы можете просто использовать strtotime вместо date_parse_from_format, чтобы получить тот же результат. Например:

 $textdate = $date; $datetime = strtotime($textdate); $datearray = date_parse($datetime); print_r($datearray); 

Это работает с PHP 5.2