2011-07-12 61 views
5

Vì date_parse_from_format() chỉ có sẵn trong PHP 5.3, tôi cần phải viết một hàm bắt chước hành vi của nó trong PHP 5.2.PHP date_parse_from_format() thay thế trong PHP 5.2

Có thể viết hàm này cho PHP 5.2 và làm cho nó hoạt động chính xác giống như cách thực hiện trong PHP 5.3 không?

Ví dụ:

Đối với đầu vào này:

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

tôi cần đầu ra này:

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] => 
) 
+0

Liệu 'strtotime() 'không hoạt động? – Michael

Trả lời

6
<?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; 
} 
?> 

Ví dụ 1:

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

Output 1:

Mảng ( [tháng] => 03 [ngày] => 23 [năm] => 2011 )

Ví dụ 2:

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

Output 2:

Mảng ( [năm] => 2011 [month] => 03 [ngày] => 23 [giờ] => 12 [phút] => 03 [thứ hai] => 00 )

+0

Cảm ơn bạn đã giúp đỡ của bạn, nhưng đầu ra cần phải được chính xác giống nhau từ bản gốc php 5.3 chức năng. – Acacio

+3

Chính xác? Tại sao? Không thể nào. Có lẽ bạn nên viết một lá thư rất tốt đẹp cho gia đình PHP yêu cầu họ quay lại nó với 5.2. Oh no wait 5.2 không được hỗ trợ tích cực nữa = p – Rudie

2

Nếu bạn muốn nó được chính xác như PHP 5.3 chức năng, bạn đang gonna cần rất nhiều mã. Tôi muốn bắt đầu với một cái gì đó như thế này:

$format = '\Y: Y-m-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', '[A-Z][a-z]{2}'), 
    'F' => array('month', '[A-Z][a-z]{2,8}'), 
    'D' => array('day', '[A-Z][a-z]{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"; 
} 

Kết quả:

string(9) "\Y: Y-m-d" 
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 
) 

Incomplete và không hoàn hảo.

5

Đây là phiên bản cải tiến của tôi và tôi nghĩ là hoàn tất. Chỉ có lỗi và cảnh báo không được tính đến.

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', '[A-Z][a-z]{3}'),  //Mois, en trois lettres, en anglais 
      'F' => array('month', '[A-Z][a-z]{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', '[A-Z][a-z]{2}'),  //Jour de la semaine, en trois lettres (et en anglais) 
      'l' => array('day', '[A-Z][a-z]{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; 
    } 
} 
+0

Wow. Bạn thực sự đã đánh cắp câu trả lời của tôi. Classy. – Rudie

+0

Hoạt động như một sự quyến rũ! Tnx. –

1

Trước tiên tôi muốn cảm ơn @rudie vì câu trả lời của anh ấy và @jeremy sàng lọc câu trả lời của anh ấy.

Tôi cần phiên bản linh hoạt hơn một chút có thể xử lý jQueryUI Datepicker bằng plugin TimePicker. Tôi cũng cần nó để làm việc với các ký tự thoát dấu gạch chéo \ để đối phó với các định dạng thời gian lẻ mà người dùng nhập như H\h i\m\i\n.

Đây là giải pháp của tôi dựa trên các câu trả lời trước đó mà tôi đã triển khai trong Connections Business Directory WordPress plugin của mình.

Kết hợp chặt chẽ hơn với chức năng của date_parse_from_format()DateTime::createFromFormat().

Hy vọng điều này sẽ giúp ai đó!

<?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', '[A-Z][a-z]{2}'), // Month ABBR 3 letters 
     'F' => array('month', '[A-Z][a-z]{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', '[A-Z][a-z]{2}'),  // Day ABBR 3 Letters 
     'l' => array('day', '[A-Z][a-z]{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); 
    } 
} 
0

Trong trường hợp bạn không cần 4 lĩnh vực cuối cùng của mảng bạn có thể chỉ cần sử dụng strtotime thay vì date_parse_from_format để có được kết quả tương tự. Ví dụ:

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

này làm việc với PHP 5.2