PHP date_parse_from_format() 函数
date_parse_from_format() 函数根据指定的格式解析日期时间字符串,返回包含详细日期时间信息的数组。与 date_parse() 函数不同,此函数可以处理自定义格式的日期字符串。
提示: 这个函数特别适用于解析非标准格式的日期字符串,例如来自第三方API或用户自定义格式的日期数据。
语法
array date_parse_from_format ( string $format , string $datetime )
参数说明
| 参数 |
描述 |
必需 |
$format |
日期时间字符串的格式,使用与 date() 相同的格式化字符 |
是 |
$datetime |
要解析的日期时间字符串 |
是 |
返回值
- 数组 - 包含解析后的日期时间信息,如果解析失败则返回 false
- 返回数组包含年、月、日、时、分、秒等详细信息
- 包含警告和错误信息,便于调试
返回数组结构
| 键名 |
描述 |
示例值 |
year |
年份 |
2024 |
month |
月份(1-12) |
3 |
day |
日期(1-31) |
15 |
hour |
小时(0-23) |
14 |
minute |
分钟(0-59) |
30 |
second |
秒(0-59) |
45 |
fraction |
微秒部分(秒的小数部分) |
0.123456 |
warning_count |
警告数量 |
2 |
warnings |
警告信息数组 |
['12' => 'The parsed date was invalid'] |
error_count |
错误数量 |
1 |
errors |
错误信息数组 |
['0' => 'Unexpected data found.'] |
is_localtime |
是否包含本地时间信息 |
true |
zone_type |
时区类型(1=UTC偏移,2=时区缩写,3=时区标识符) |
1 |
zone |
时区偏移(秒) |
28800 |
is_dst |
是否夏令时 |
false |
示例代码
示例 1:基本用法
<?php
// 解析标准格式日期
$dateStr = "2024-03-15 14:30:45";
$format = "Y-m-d H:i:s";
$parsed = date_parse_from_format($format, $dateStr);
echo "解析日期: {$dateStr}<br>";
echo "使用格式: {$format}<br><br>";
echo "解析结果:<br>";
echo "年: " . ($parsed['year'] ?? 'N/A') . "<br>";
echo "月: " . ($parsed['month'] ?? 'N/A') . "<br>";
echo "日: " . ($parsed['day'] ?? 'N/A') . "<br>";
echo "时: " . ($parsed['hour'] ?? 'N/A') . "<br>";
echo "分: " . ($parsed['minute'] ?? 'N/A') . "<br>";
echo "秒: " . ($parsed['second'] ?? 'N/A') . "<br>";
if (isset($parsed['warning_count']) && $parsed['warning_count'] > 0) {
echo "警告数量: " . $parsed['warning_count'] . "<br>";
}
if (isset($parsed['error_count']) && $parsed['error_count'] > 0) {
echo "错误数量: " . $parsed['error_count'] . "<br>";
}
/*
输出:
解析日期: 2024-03-15 14:30:45
使用格式: Y-m-d H:i:s
解析结果:
年: 2024
月: 3
日: 15
时: 14
分: 30
秒: 45
*/
?>
示例 2:解析自定义格式
<?php
// 解析各种自定义格式
$testCases = [
[
'format' => 'd/m/Y',
'date' => '15/03/2024',
'desc' => '欧洲日期格式'
],
[
'format' => 'm/d/Y H:i A',
'date' => '03/15/2024 02:30 PM',
'desc' => '美国日期时间格式'
],
[
'format' => 'Y年m月d日 H时i分s秒',
'date' => '2024年03月15日 14时30分45秒',
'desc' => '中文日期时间格式'
],
[
'format' => 'D, d M Y H:i:s T',
'date' => 'Fri, 15 Mar 2024 14:30:45 CST',
'desc' => 'RFC 2822格式'
],
[
'format' => 'Y-m-d\TH:i:s.uP',
'date' => '2024-03-15T14:30:45.123456+08:00',
'desc' => 'ISO 8601带微秒和时区'
],
];
foreach ($testCases as $case) {
echo "<strong>{$case['desc']}:</strong><br>";
echo "格式: {$case['format']}<br>";
echo "日期: {$case['date']}<br>";
$parsed = date_parse_from_format($case['format'], $case['date']);
if ($parsed === false) {
echo "解析失败<br>";
} else {
echo "解析结果: " .
"{$parsed['year']}-{$parsed['month']}-{$parsed['day']} " .
"{$parsed['hour']}:{$parsed['minute']}:{$parsed['second']}<br>";
if (isset($parsed['fraction']) && $parsed['fraction'] > 0) {
echo "微秒: " . $parsed['fraction'] . "<br>";
}
if (isset($parsed['zone'])) {
echo "时区偏移: " . ($parsed['zone'] / 3600) . "小时<br>";
}
}
echo "<br>";
}
?>
示例 3:错误处理与验证
<?php
// 错误处理与验证
function validateDateWithFormat($dateString, $format) {
$parsed = date_parse_from_format($format, $dateString);
if ($parsed === false) {
return [
'valid' => false,
'message' => '无法解析日期字符串',
'errors' => [],
'warnings' => []
];
}
// 检查错误和警告
$hasErrors = isset($parsed['error_count']) && $parsed['error_count'] > 0;
$hasWarnings = isset($parsed['warning_count']) && $parsed['warning_count'] > 0;
// 验证日期是否有效
$isValidDate = false;
if (isset($parsed['year'], $parsed['month'], $parsed['day'])) {
$isValidDate = checkdate($parsed['month'], $parsed['day'], $parsed['year']);
}
// 验证时间是否有效
$isValidTime = true;
if (isset($parsed['hour']) && ($parsed['hour'] < 0 || $parsed['hour'] > 23)) {
$isValidTime = false;
}
if (isset($parsed['minute']) && ($parsed['minute'] < 0 || $parsed['minute'] > 59)) {
$isValidTime = false;
}
if (isset($parsed['second']) && ($parsed['second'] < 0 || $parsed['second'] > 59)) {
$isValidTime = false;
}
$messages = [];
if (!$isValidDate) {
$messages[] = '无效的日期';
}
if (!$isValidTime) {
$messages[] = '无效的时间';
}
if ($hasErrors && isset($parsed['errors'])) {
$messages[] = '解析错误: ' . implode(', ', $parsed['errors']);
}
if ($hasWarnings && isset($parsed['warnings'])) {
$messages[] = '解析警告: ' . implode(', ', $parsed['warnings']);
}
return [
'valid' => $isValidDate && $isValidTime && !$hasErrors,
'message' => empty($messages) ? '日期有效' : implode('; ', $messages),
'parsed' => $parsed,
'errors' => $hasErrors ? $parsed['errors'] : [],
'warnings' => $hasWarnings ? $parsed['warnings'] : [],
'date_info' => [
'year' => $parsed['year'] ?? null,
'month' => $parsed['month'] ?? null,
'day' => $parsed['day'] ?? null,
'hour' => $parsed['hour'] ?? null,
'minute' => $parsed['minute'] ?? null,
'second' => $parsed['second'] ?? null,
]
];
}
// 测试各种日期验证
$testDates = [
['date' => '2024-03-15', 'format' => 'Y-m-d', 'desc' => '有效日期'],
['date' => '2024-02-30', 'format' => 'Y-m-d', 'desc' => '无效日期(2月30日)'],
['date' => '2024-03-15 25:61:61', 'format' => 'Y-m-d H:i:s', 'desc' => '无效时间'],
['date' => '15/03/2024', 'format' => 'Y-m-d', 'desc' => '格式不匹配'],
['date' => '2024年03月15日', 'format' => 'Y年m月d日', 'desc' => '中文格式有效'],
];
foreach ($testDates as $test) {
echo "<strong>测试: {$test['desc']}</strong><br>";
echo "日期: {$test['date']}, 格式: {$test['format']}<br>";
$result = validateDateWithFormat($test['date'], $test['format']);
echo "状态: " . ($result['valid'] ? '✅ 有效' : '❌ 无效') . "<br>";
echo "消息: {$result['message']}<br>";
if (!$result['valid'] && !empty($result['errors'])) {
echo "错误详情:<br>";
foreach ($result['errors'] as $pos => $msg) {
echo "位置 {$pos}: {$msg}<br>";
}
}
echo "<br>";
}
?>
示例 4:与相关函数比较
<?php
// 与相关函数的比较
echo "日期解析函数比较:<br><br>";
$dateString = "15/03/2024 14:30:45";
$format = "d/m/Y H:i:s";
echo "日期字符串: {$dateString}<br>";
echo "格式: {$format}<br><br>";
// 1. date_parse_from_format()
echo "<strong>1. date_parse_from_format():</strong><br>";
$parsed1 = date_parse_from_format($format, $dateString);
if ($parsed1 !== false) {
echo "成功解析<br>";
echo "结果: {$parsed1['year']}-{$parsed1['month']}-{$parsed1['day']} {$parsed1['hour']}:{$parsed1['minute']}:{$parsed1['second']}<br>";
} else {
echo "解析失败<br>";
}
// 2. date_create_from_format() / DateTime::createFromFormat()
echo "<br><strong>2. date_create_from_format():</strong><br>";
$date2 = date_create_from_format($format, $dateString);
if ($date2 !== false) {
echo "成功创建DateTime对象<br>";
echo "格式化输出: " . date_format($date2, 'Y-m-d H:i:s') . "<br>";
} else {
echo "创建失败<br>";
}
// 3. strtotime() + date()
echo "<br><strong>3. strtotime():</strong><br>";
$timestamp = strtotime($dateString);
if ($timestamp !== false) {
echo "成功解析为时间戳<br>";
echo "格式化输出: " . date('Y-m-d H:i:s', $timestamp) . "<br>";
echo "注意: strtotime可能将15/03/2024解释为3月15日(美国格式)<br>";
} else {
echo "解析失败<br>";
}
// 4. date_parse()(无格式)
echo "<br><strong>4. date_parse():</strong><br>";
$parsed4 = date_parse($dateString);
echo "解析结果: ";
if ($parsed4 !== false) {
if ($parsed4['error_count'] > 0) {
echo "有错误,无法正确解析此格式<br>";
} else {
echo "{$parsed4['year']}-{$parsed4['month']}-{$parsed4['day']} {$parsed4['hour']}:{$parsed4['minute']}:{$parsed4['second']}<br>";
}
}
// 性能比较
echo "<br><strong>性能比较 (1000次迭代):</strong><br>";
$iterations = 1000;
// date_parse_from_format
$start1 = microtime(true);
for ($i = 0; $i < $iterations; $i++) {
$parsed = date_parse_from_format($format, $dateString);
}
$time1 = microtime(true) - $start1;
// date_create_from_format
$start2 = microtime(true);
for ($i = 0; $i < $iterations; $i++) {
$date = date_create_from_format($format, $dateString);
}
$time2 = microtime(true) - $start2;
// strtotime
$start3 = microtime(true);
for ($i = 0; $i < $iterations; $i++) {
$timestamp = strtotime($dateString);
}
$time3 = microtime(true) - $start3;
echo "date_parse_from_format: " . number_format($time1 * 1000, 2) . " ms<br>";
echo "date_create_from_format: " . number_format($time2 * 1000, 2) . " ms<br>";
echo "strtotime: " . number_format($time3 * 1000, 2) . " ms<br>";
?>
示例 5:实用工具函数
<?php
/**
* 日期解析实用工具类
*/
class DateParserUtils {
/**
* 尝试多种格式解析日期
*/
public static function parseDateMultipleFormats($dateString, $formats = null) {
if ($formats === null) {
// 常用日期格式
$formats = [
'Y-m-d H:i:s',
'Y-m-d',
'd/m/Y H:i:s',
'd/m/Y',
'm/d/Y H:i:s',
'm/d/Y',
'Y年m月d日 H时i分s秒',
'Y年m月d日',
'Y.m.d H:i:s',
'Y.m.d',
'd-m-Y H:i:s',
'd-m-Y',
'Y/m/d H:i:s',
'Y/m/d',
];
}
$results = [];
foreach ($formats as $format) {
$parsed = date_parse_from_format($format, $dateString);
if ($parsed !== false &&
isset($parsed['year'], $parsed['month'], $parsed['day']) &&
$parsed['error_count'] == 0) {
// 验证日期有效性
if (checkdate($parsed['month'], $parsed['day'], $parsed['year'])) {
$results[] = [
'format' => $format,
'parsed' => $parsed,
'date' => sprintf(
'%04d-%02d-%02d %02d:%02d:%02d',
$parsed['year'],
$parsed['month'],
$parsed['day'],
$parsed['hour'] ?? 0,
$parsed['minute'] ?? 0,
$parsed['second'] ?? 0
),
'confidence' => self::calculateFormatConfidence($parsed, $format, $dateString)
];
}
}
}
// 按置信度排序
usort($results, function($a, $b) {
return $b['confidence'] <=> $a['confidence'];
});
return $results;
}
/**
* 计算格式匹配的置信度
*/
private static function calculateFormatConfidence($parsed, $format, $dateString) {
$confidence = 100;
// 如果有警告,降低置信度
if (isset($parsed['warning_count']) && $parsed['warning_count'] > 0) {
$confidence -= $parsed['warning_count'] * 10;
}
// 检查是否有未使用的数据
$expectedLength = strlen($dateString);
$parsedLength = 0;
if (isset($parsed['hour'])) $parsedLength += 2;
if (isset($parsed['minute'])) $parsedLength += 2;
if (isset($parsed['second'])) $parsedLength += 2;
// 格式越完整,置信度越高
$formatComplexity = strlen($format);
$confidence += $formatComplexity * 0.5;
return max(0, min(100, $confidence));
}
/**
* 将解析结果转换为DateTime对象
*/
public static function parsedToDateTime($parsed) {
if (!isset($parsed['year'], $parsed['month'], $parsed['day'])) {
return false;
}
$dateStr = sprintf(
'%04d-%02d-%02d %02d:%02d:%02d',
$parsed['year'],
$parsed['month'],
$parsed['day'],
$parsed['hour'] ?? 0,
$parsed['minute'] ?? 0,
$parsed['second'] ?? 0
);
if (isset($parsed['fraction']) && $parsed['fraction'] > 0) {
$dateStr .= '.' . $parsed['fraction'];
}
try {
$date = new DateTime($dateStr);
// 设置时区
if (isset($parsed['zone']) && $parsed['is_localtime']) {
$offset = $parsed['zone'];
$timezone = timezone_name_from_abbr('', $offset, 0);
if ($timezone) {
$date->setTimezone(new DateTimeZone($timezone));
}
}
return $date;
} catch (Exception $e) {
return false;
}
}
/**
* 获取日期字符串的详细信息
*/
public static function getDateDetails($dateString, $format = null) {
if ($format === null) {
// 尝试自动检测
$parsedResults = self::parseDateMultipleFormats($dateString);
if (empty($parsedResults)) {
return false;
}
$bestMatch = $parsedResults[0];
$parsed = $bestMatch['parsed'];
$detectedFormat = $bestMatch['format'];
} else {
$parsed = date_parse_from_format($format, $dateString);
if ($parsed === false) {
return false;
}
$detectedFormat = $format;
}
$dateTime = self::parsedToDateTime($parsed);
if ($dateTime === false) {
return false;
}
return [
'original_string' => $dateString,
'detected_format' => $detectedFormat,
'parsed_data' => $parsed,
'datetime' => $dateTime,
'formats' => [
'iso' => $dateTime->format('c'),
'rfc2822' => $dateTime->format('r'),
'mysql' => $dateTime->format('Y-m-d H:i:s'),
'human' => $dateTime->format('l, F j, Y g:i A'),
'timestamp' => $dateTime->getTimestamp(),
],
'validation' => [
'is_valid_date' => checkdate(
$parsed['month'] ?? 1,
$parsed['day'] ?? 1,
$parsed['year'] ?? 1970
),
'error_count' => $parsed['error_count'] ?? 0,
'warning_count' => $parsed['warning_count'] ?? 0,
'errors' => $parsed['errors'] ?? [],
'warnings' => $parsed['warnings'] ?? [],
]
];
}
}
echo "日期解析实用工具示例:<br><br>";
// 测试多格式解析
echo "<strong>1. 多格式日期解析:</strong><br>";
$dateStrings = [
'2024-03-15 14:30:45',
'15/03/2024',
'03/15/2024 02:30 PM',
'2024年03月15日',
'15-03-2024 14:30',
];
foreach ($dateStrings as $dateStr) {
echo "解析: {$dateStr}<br>";
$results = DateParserUtils::parseDateMultipleFormats($dateStr);
if (!empty($results)) {
$best = $results[0];
echo "最佳匹配格式: {$best['format']}<br>";
echo "解析结果: {$best['date']}<br>";
echo "置信度: {$best['confidence']}%<br>";
} else {
echo "无法解析<br>";
}
echo "<br>";
}
// 测试日期详情获取
echo "<strong>2. 日期详情获取:</strong><br>";
$testDate = '2024-03-15 14:30:45.123456';
$details = DateParserUtils::getDateDetails($testDate);
if ($details !== false) {
echo "原始字符串: {$details['original_string']}<br>";
echo "检测格式: {$details['detected_format']}<br>";
echo "ISO格式: {$details['formats']['iso']}<br>";
echo "时间戳: {$details['formats']['timestamp']}<br>";
echo "可读格式: {$details['formats']['human']}<br>";
if ($details['validation']['error_count'] > 0) {
echo "错误: " . implode(', ', $details['validation']['errors']) . "<br>";
}
} else {
echo "无法获取日期详情<br>";
}
?>
注意事项
重要提示:
- date_parse_from_format() 返回的是数组,而不是 DateTime 对象
- 函数会尽可能解析日期,即使有错误或警告也会返回结果
- 解析结果中的年月日可能为 false,表示解析失败
- 时区信息只有在日期字符串中包含时区信息时才会被解析
- 微秒部分(fraction)以小数形式返回,如 0.123456 表示 123456 微秒
- 对于无效的日期(如2月30日),函数会返回解析结果但不验证有效性
- 使用 checkdate() 函数验证解析出的日期是否有效
常见错误和警告信息
| 错误/警告 |
描述 |
常见原因 |
Unexpected data found. |
发现意外的数据 |
日期字符串比格式字符串长 |
Data missing |
数据缺失 |
日期字符串比格式字符串短 |
The parsed date was invalid |
解析的日期无效 |
如2月30日、13月等 |
Double time specification |
重复的时间规范 |
格式中指定了两次小时/分钟/秒 |
Trailing data |
尾部数据 |
日期字符串末尾有多余字符 |
相关函数
| 函数 |
描述 |
date_create_from_format() |
根据格式创建DateTime对象 |
date_parse() |
解析日期字符串(自动检测格式) |
strtotime() |
将英文文本日期时间解析为Unix时间戳 |
checkdate() |
验证日期的有效性 |
DateTime::createFromFormat() |
面向对象的格式化日期创建方法 |
date_get_last_errors() |
获取上次日期解析的错误信息 |