DateTime::createFromFormat('Ymd', '19991223')
//Expected date: 1999-12-23
DateTime::createFromFormat('Ymd', '19991323')
//Overflow to next year: 2000-01-23
DateTime::createFromFormat('Ymd', '19991423')
//Overflow to next year: 2000-02-23
$inputDateString = '19992323';
$date = DateTime::createFromFormat(
'Ymd',
filter_var(
$inputDateString,
FILTER_CALLBACK,
[
'options' => function($date) {
// Does the input string have the correct date format?
if(!preg_match('/^(?<Y>[0-9]{4})(?<m>[0-9]{2})(?<d>[0-9]{2})$/', $date, $parts)) {
return false;
}
// Is the year within a given range?
// Current range is between 0 and the current server year.
if(
!filter_var(
$parts['Y'],
FILTER_VALIDATE_INT,
[
'options' => [
// Minimum year
'min_range' => 0,
// Maximum year
'max_range' => date('Y')
]
]
)
) {
return false;
}
// Is the month between 1 and 12?
if(
!filter_var(
$parts['m'],
FILTER_VALIDATE_INT,
[
'options' => [
// January
'min_range' => 1,
// December
'max_range' => 12
]
]
)
) {
return false;
}
$lastDayOfMonth =
(DateTime::createFromFormat('Ymd', $parts['Y'] . $parts['m'] . '01'))
->modify('last day of this month');
// Is the day between 1 and the last day of the
// given month and year?
if(
!filter_var(
$parts['d'],
FILTER_VALIDATE_INT,
[
'options' => [
// First day of month
'min_range' => 1,
// Last day of month
'max_range' => $lastDayOfMonth->format('d')
]
]
)
) {
return false;
}
return $date;
}
]
)
);
var_dump($date); // $date is false since month is greater than 12
// $date would be a DateTime object if the input date string were valid.
5条答案
按热度按时间mmvthczy1#
m
允许上级12的数字(php.net)。m:01至12或1至12。(接受大于12的两位数字,在这种情况下,它们将使年份溢出。例如,使用13表示下一年的1月)
这就是你的约会所发生的事情,它会溢出到下一年。
示例:
myzjeezk2#
虽然可能有点天真,但您应该能够假设,如果您使用格式解析日期,然后使用该格式对其进行格式化,并获得与您输入的字符串相同的字符串,那么日期可能是有效的。
输出量:
最明显的警告是,并不是所有的解析和格式说明符都是共享的,有些可能会插入解析。接受任意精度但输出固定精度的小数秒。
uttx8gqw3#
PHP的
DateTime
函数和类方法有些宽容,并不意味着要用于严格验证。然而,考虑到你只有一个简单的年、月和日,写一个验证函数是很简单的:pw136qt24#
PHP中的DateTime::DataFromFormat函数并不严格执行格式,它会尝试尽可能多地解析输入字符串。在您的示例中,它将“1999-23-23”解释为“1999-23-23”,然后将其调整为有效日期。如果你想检查日期是否有效,你可以这样做:
t30tvxxf5#
这是一个我们必须接受的不幸的设计决定:
换句话说,要获得严格的字符串解析,您需要额外的手动步骤并检查警告和(我认为,不是100%确定)错误。如果没有这一点,PHP将尽最大努力“修复”输入并产生一个日期,不管是什么(例如。如果没有闰年,就把2月29日变成3月1日)。
我建议你创建一个 Package 器函数,让它为每个无效的输入(
null
或false
)返回一个标志值,或者抛出一个异常。一个可能的例子:Demo