7

我正在尝试制作日期正则表达式验证器。我遇到的问题是我正在使用带有"date"类型的输入字段,这在 Chrome 中就像一个魅力;它在 Chrome 中打开了一个类似日历的功能,但在其余部分它什么也不做,所以我决定手动输入其余部分的日期。

这是我的错误抛出消息(我正在寻找 YYYY-MM-DD 格式):

$date_regex ='#^(19|20)\d\d[\- /.](0[1-9]|1[012])[\- /.](0[1-9]|[12][0-9]|3[01])$#';
$hiredate = $_POST['hiredate'];
if (!preg_match($date_regex, $hiredate)){
    $errors[] = 'Your hire date entry does not match the YYYY-MM-DD required format.';
}

我知道有很多关于这个的例子,但我已经尝试了 20 个,但我无法解决它。也许我错过了一些东西。

这是输入字段,如果有些相关:

<input type="date" name="hiredate" />
4

3 回答 3

15

不要为此使用正则表达式,您可以通过使用获得相同的结果DateTime::createFromFormat

// specify your date's original format, in this example m/d/Y (e.g. 08/31/2013)
$format = "m/d/Y";
$hireDate = DateTime::createFromFormat($format, $_POST['hiredate']);
if(!$hireDate) {
 // createFromFormat returns false if the format is invalid;
} else {
   //change it to any format you want with format() (e.g. 2013-08-31)
   echo $hireDate->format("Y-m-d");
}

你可以在这里阅读更多:

http://php.net/manual/en/datetime.createfromformat.php

但是,似乎该问题与 PHP 完全无关。

PHP 在后端运行,您似乎遇到了前端问题。

我也怀疑问题出在您使用的输入类型上。如果某个浏览器不支持您指定的输入类型,则默认为文本。在这里看到它:

http://jsfiddle.net/FKGCA/

我的浏览器不知道<input type="whatever" />它是什么,所以它默认输入类型为“文本”。如果我将这 4 个输入包装在一个<form action="myForm.php" method="POST"></form>标签中,浏览器会将输入发送到服务器,因为服务器不关心/知道输入是否隐藏、单选按钮、选择、文本或密码。服务器只接收原始数据。

您的问题很可能出在您的 Javascript 上,而不是您的 PHP 上。尝试查看不显示您的小部件的浏览器是否告诉您页面中存在某种错误。

Safari 和 Firefox 有开发/调试工具,对 IE 不太确定。

于 2013-11-04T17:45:42.420 回答
10

您的正则表达式不起作用,因为您有未转义 /的分隔符。

YYYY-MM-DD将以如下格式验证日期的正则表达式:

^(19|20)\d\d[\-\/.](0[1-9]|1[012])[\-\/.](0[1-9]|[12][0-9]|3[01])$

它将验证年份是否以19or开头20,月份不大于12且不等于0,日期不大于31且不等于0

在线示例

使用您的初始示例,您可以像这样测试它:

$date_regex = '/^(19|20)\d\d[\-\/.](0[1-9]|1[012])[\-\/.](0[1-9]|[12][0-9]|3[01])$/';
$hiredate = '2013-14-04';

if (!preg_match($date_regex, $hiredate)) {
    echo '<br>Your hire date entry does not match the YYYY-MM-DD required format.<br>';
} else {
    echo '<br>Your date is set correctly<br>';      
}

在线示例

于 2013-11-04T18:04:57.947 回答
0

YYYY-MM-DD在一行语句中检查和验证日期

function isValidDate($date) {
    return preg_match("/^(\d{4})-(\d{1,2})-(\d{1,2})$/", $date, $m)
        ? checkdate(intval($m[2]), intval($m[3]), intval($m[1]))
        : false;
}

请在此处查看我的答案中的详细信息。

不要盲目使用DateTime::createFromFormat来验证日期。让我们取一个不存在的日期2018-02-30,看看:

$d = DateTime::createFromFormat("Y-m-d", "2018-02-30");
var_dump((bool) $d); // bool(true)

是的,它返回true,不像false您预期​​的那样。更有意思的:

$d = DateTime::createFromFormat("Y-m-d", "2018-99-99");
var_dump((bool) $d); // bool(true)

另外true......所以,它只验证位数。再试一次:

$d = DateTime::createFromFormat("Y-m-d", "ABCD-99-99");
var_dump($d); // bool(false)

终于false

我们可以从这个片段中看到这里发生了什么:

$d = DateTime::createFromFormat("Y-m-d", "2018-02-30");
var_dump($d);

// var_dump OUTPUT
object(DateTime)#1 (3) {
  ["date"]=>
  string(26) "2018-03-02 16:41:34.000000"
  ["timezone_type"]=>
  int(3)
  ["timezone"]=>
  string(3) "UTC"
}

如您所见,当我们传递 non-existent2018-02-30时,DateTime对象包含2018-03-02. 我假设这是因为 2018 年 2 月有 28 天,即最大日期是2018-02-28,当我们过了一天时30, createFromFormat 只是在 30 天后2018-02-01创建新日期,而没有任何先前的日期验证。

于 2017-11-19T16:55:15.237 回答