* Date : 2018-11-07 * Version : 1.0 */ namespace Helper; defined('APP_CHARSET') or define('APP_CHARSET', 'utf-8'); class DateTimeParser { /* @var bool 标志 php 的 "mbstring" 扩展是否为可用状态 */ static private $_mbstringAvailable; /** * 将日期转化成时间戳 * @param string $value * @param string $pattern * @param array $defaults 年,月,日,小时,分钟和秒的默认值 * @return int|false 如果解析失败,则返回False */ static public function parse($value, $pattern = 'MM/dd/yyyy', $defaults = []) { if (null === self::$_mbstringAvailable) { self::$_mbstringAvailable = extension_loaded('mbstring'); } $ps = self::analysisPattern($pattern); $i = 0; $n = self::$_mbstringAvailable ? mb_strlen($value, APP_CHARSET) : strlen($value); foreach ($ps as $p) { switch ($p) { case 'yyyy': { if (false === ($year = self::parseInteger($value, $i, 4, 4))) return false; $i += 4; break; } case 'yy': { if (false === ($year = self::parseInteger($value, $i, 1, 2))) return false; $i += strlen($year); break; } case 'MM': { if (false === ($month = self::parseInteger($value, $i, 2, 2))) return false; $i += 2; break; } case 'M': { if (false === ($month = self::parseInteger($value, $i, 1, 2))) return false; $i += strlen($month); break; } case 'dd': { if (false === ($day = self::parseInteger($value, $i, 2, 2))) return false; $i += 2; break; } case 'd': { if (false === ($day = self::parseInteger($value, $i, 1, 2))) return false; $i += strlen($day); break; } case 'h': case 'H': { if (false === ($hour = self::parseInteger($value, $i, 1, 2))) return false; $i += strlen($hour); break; } case 'hh': case 'HH': { if (false === ($hour = self::parseInteger($value, $i, 2, 2))) return false; $i += 2; break; } case 'm': { if (false === ($minute = self::parseInteger($value, $i, 1, 2))) return false; $i += strlen($minute); break; } case 'mm': { if (false === ($minute = self::parseInteger($value, $i, 2, 2))) return false; $i += 2; break; } case 's': { if (false === ($second = self::parseInteger($value, $i, 1, 2))) return false; $i += strlen($second); break; } case 'ss': { if (false === ($second = self::parseInteger($value, $i, 2, 2))) return false; $i += 2; break; } case 'a': { if (false === ($ampm = self::parseAmPm($value, $i))) return false; if (isset($hour)) { if ($hour == 12 && $ampm === 'am') $hour = 0; else if ($hour < 12 && $ampm === 'pm') $hour += 12; } $i += 2; break; } default: { $tn = self::$_mbstringAvailable ? mb_strlen($p, APP_CHARSET) : strlen($p); if ($i >= $n || ($p{0} != '?' && (self::$_mbstringAvailable ? mb_substr($value, $i, $tn, APP_CHARSET) : substr($value, $i, $tn)) !== $p)) return false; $i += $tn; break; } } } if ($i < $n) return false; if (!isset($year)) $year = isset($defaults['year']) ? $defaults['year'] : date('Y'); if (!isset($month)) $month = isset($defaults['month']) ? $defaults['month'] : date('n'); if (!isset($day)) $day = isset($defaults['day']) ? $defaults['day'] : date('j'); if (strlen($year) === 2) { $year = Unit::getFullYear($year); } $year = (int)$year; $month = (int)$month; $day = (int)$day; if ( !isset($hour) && !isset($minute) && !isset($second) && !isset($defaults['hour']) && !isset($defaults['minute']) && !isset($defaults['second']) ) { $hour = $minute = $second = 0; } else { if (!isset($hour)) { $hour = isset($defaults['hour']) ? $defaults['hour'] : date('H'); } if (!isset($minute)) { $minute = isset($defaults['minute']) ? $defaults['minute'] : date('i'); } if (!isset($second)) { $second = isset($defaults['second']) ? $defaults['second'] : date('s'); } $hour = (int)$hour; $minute = (int)$minute; $second = (int)$second; } if (Unit::isValidDate($year, $month, $day) && Unit::isValidTime($hour, $minute, $second)) { return Unit::getTimestamp($hour, $minute, $second, $month, $day, $year); } return false; } /** * 解析日期或时间的格式串 * @param string $pattern * @return array */ static protected function analysisPattern($pattern) { if (!($n = self::$_mbstringAvailable ? mb_strlen($pattern, APP_CHARSET) : strlen($pattern))) { return []; } $ps = []; $c0 = self::$_mbstringAvailable ? mb_substr($pattern, 0, 1, APP_CHARSET) : substr($pattern, 0, 1); for ($start = 0, $i = 1; $i < $n; ++$i) { $c = self::$_mbstringAvailable ? mb_substr($pattern, $i, 1, APP_CHARSET) : substr($pattern, $i, 1); if ($c !== $c0) { $ps[] = self::$_mbstringAvailable ? mb_substr($pattern, $start, $i - $start, APP_CHARSET) : substr($pattern, $start, $i - $start); $c0 = $c; $start = $i; } } $ps[] = self::$_mbstringAvailable ? mb_substr($pattern, $start, $n - $start, APP_CHARSET) : substr($pattern, $start, $n - $start); return $ps; } /** * 将相应的字符串转换成数字 * @param string $value the date string to be parsed * @param int $offset starting offset * @param int $minLength minimum length * @param int $maxLength maximum length * @return string parsed integer value */ static protected function parseInteger($value, $offset, $minLength, $maxLength) { for ($len = $maxLength; $len >= $minLength; --$len) { $v = self::$_mbstringAvailable ? mb_substr($value, $offset, $len, APP_CHARSET) : substr($value, $offset, $len); if (ctype_digit($v) && (self::$_mbstringAvailable ? mb_strlen($v, APP_CHARSET) : strlen($v)) >= $minLength) { return $v; } } return false; } /** * 解析上午"am"和下午"pm" * @param string $value the date string to be parsed * @param int $offset starting offset * @return string parsed day period value */ static protected function parseAmPm($value, $offset) { $v = strtolower(self::$_mbstringAvailable ? mb_substr($value, $offset, 2, APP_CHARSET) : substr($value, $offset, 2)); return $v === 'am' || $v === 'pm' ? $v : false; } }