正确确定日期字符串是不是是该格式的有效日期

Posted

技术标签:

【中文标题】正确确定日期字符串是不是是该格式的有效日期【英文标题】:Correctly determine if date string is a valid date in that format正确确定日期字符串是否是该格式的有效日期 【发布时间】:2013-10-16 18:34:11 【问题描述】:

我从 API 接收日期字符串,它的格式为 yyyy-mm-dd

我目前正在使用正则表达式来验证字符串格式,这可以正常工作,但我可以看到一些情况,根据字符串,它可能是正确的格式,但实际上是无效的日期。即2013-13-01,例如。

php 中是否有更好的方法来获取诸如 2013-13-01 之类的字符串并判断它是否是格式 yyyy-mm-dd 的有效日期?

【问题讨论】:

php date validation的可能重复 无论如何这里的答案要好得多。 【参考方案1】:

您可以为此使用DateTime::createFromFormat()

function validateDate($date, $format = 'Y-m-d')

    $d = DateTime::createFromFormat($format, $date);
    // The Y ( 4 digits year ) returns TRUE for any integer with any number of digits so changing the comparison from == to === fixes the issue.
    return $d && $d->format($format) === $date;

[函数取自this answer。也在php.net。原作者Glavić.]


测试用例:

var_dump(validateDate('2013-13-01'));  // false
var_dump(validateDate('20132-13-01')); // false
var_dump(validateDate('2013-11-32'));  // false
var_dump(validateDate('2012-2-25'));   // false
var_dump(validateDate('2013-12-01'));  // true
var_dump(validateDate('1970-12-01'));  // true
var_dump(validateDate('2012-02-29'));  // true
var_dump(validateDate('2012', 'Y'));   // true
var_dump(validateDate('12012', 'Y'));  // false

Demo!

【讨论】:

如果您使用的是 PHP 5.2.x,您应该使用 strtotime 获取 unix 时间戳,然后使用 date('Y-m-d', $t) 获取字符串日期。然后你就像这个答案一样比较它们。 @pedromanoel:对于标准日期时间输入,您可以使用strtotime,但对于strtotime 无法识别的非标准格式,您将需要一些其他解决方案。对于 php 版本 5.2 的支持于 2011 年 1 月停止,对于 5.3 的支持于 2014 年 8 月停止。 考虑这个日期var_dump( validateDate('2012-2-9')); 该功能正常工作。它返回 false,因为您指定的 thr 格式不正确。如果要使用不带前导零的日期和月份,则格式应为'Y-n-j'、@reignsly。 @AntonyD'Andrea:不,没有那个部分就行不通。因为$d 在你给它日期时不会是假的,它有溢出的部分,比如第 13 个月(2013-13-01)。但这真的取决于你想要什么。如果你需要例如validateDate('2015-55-66') 是有效的,那么是的,你只需要检查$d 是否是对象。【参考方案2】:

您还可以解析月份日期和年份的日期,然后您可以使用 PHP 函数 checkdate(),您可以在此处阅读:http://php.net/manual/en/function.checkdate.php

你也可以试试这个:

$date="2013-13-01";

if (preg_match("/^[0-9]4-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$/",$date))
    
        echo 'Date is valid';
    else
        echo 'Date is invalid';
    

【讨论】:

如果是 2 月(由elitechief21 评论) function isValidDate($date) return preg_match("/^[0-9]4-(0[1-9]|1[ 0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$/",$date) && date("Ymd", strtotime($date )) == $日期; 这个解决方案很差,因为它不检查任何意义上的日期有效性。任何一个月都可以有 31 天,包括二月。任何一年都可以有 2 月 29 日。使用 RegExp 验证日期需要更复杂的东西,包括反向引用和否定的前瞻性。【参考方案3】:

判断任何字符串是否为日期

function checkIsAValidDate($myDateString)
    return (bool)strtotime($myDateString);

【讨论】:

这验证了一系列有效的日期格式,而不仅仅是yyyy-mm-dd @MichelAyres 这是因为 php 将 2015-02-30 视为有效日期,因为当给定的日期大于给定月份(或负数)的天数时,php 会滚动到下个月。由于日期保证格式为yyyy-mm-dd,因此可以通过将返回值更改为return (bool)strtotime($myDateString) && date("Y-m-d", strtotime($myDateString)) == $myDateString; 来解决此问题。 为什么(bool)strtotime('s') 是真的? 这也返回 1 checkIsAValidDate("F"); 如果日期字符串包含斜杠(/),我们可以在返回之前使用$myDateString = str_replace("/", '-', $myDateString);,例如:-dd/mm/yyyy【参考方案4】:

简单的使用php预建函数:

function checkmydate($date) 
  $tempDate = explode('-', $date);
  // checkdate(month, day, year)
  return checkdate($tempDate[1], $tempDate[2], $tempDate[0]);

测试

   checkmydate('2015-12-01'); //true
   checkmydate('2015-14-04'); //false

【讨论】:

不错的简单解决方案,第一次工作,谢谢:) 再次,当使用测试时,在if 内简单地返回truefalse,返回测试本身。 假设 $tempDate 数组中至少有 3 个元素。 @person27: return sizeof($tmpDate) == 3 && checkdate($tmpDate[1]... @vineet - 这失败了。如果年份是 2202022020 或者即使年份是 20201 - 它每次都返回 true。【参考方案5】:

此选项不仅简单,而且几乎可以接受任何格式,尽管使用非标准格式可能会出现问题。

$timestamp = strtotime($date);
return $timestamp ? $date : null;

【讨论】:

这应该是公认的答案!简单得多。 需要注意的是,这不适用于英式 (d/m/Y) 格式,因为它会假定它正在转换美式 (m/d/Y)。它似乎只有在当天低于 12 点时才有效! @galki - 我对此进行了测试,但它未能通过某些值。如果 $date = '202-03-31' 它返回 true。但这不是一个有效的日期。我发现如果您将年份更改为无效年份,它总是返回 true。 @rolinger 奇怪...也许它看到的是 202AD? “strtotime”给出的是哪一年的时间戳? @rolinger 对于相同的结果,它更慢且代码更多。 '202-03-31' 是 3 世纪的真实日期,我不明白你为什么声称它不是有效日期。【参考方案6】:

根据 cl-sah 的回答,但这听起来更好,更短......

function checkmydate($date) 
  $tempDate = explode('-', $date);
  return checkdate($tempDate[1], $tempDate[2], $tempDate[0]);

测试

checkmydate('2015-12-01');//true
checkmydate('2015-14-04');//false

【讨论】:

你需要测试count($tempDate) === 3虽然 @VDarricau 不,如果它们丢失,checkdate 会炸弹,你可以为每一个都写 isset() 但我会简单地抑制警告【参考方案7】:

判断字符串是否为日期,即使字符串是非标准格式

(strtotime 不接受任何自定义格式)

<?php
function validateDateTime($dateStr, $format)

    date_default_timezone_set('UTC');
    $date = DateTime::createFromFormat($format, $dateStr);
    return $date && ($date->format($format) === $dateStr);


// These return true
validateDateTime('2001-03-10 17:16:18', 'Y-m-d H:i:s');
validateDateTime('2001-03-10', 'Y-m-d');
validateDateTime('2001', 'Y');
validateDateTime('Mon', 'D');
validateDateTime('March 10, 2001, 5:16 pm', 'F j, Y, g:i a');
validateDateTime('March 10, 2001, 5:16 pm', 'F j, Y, g:i a');
validateDateTime('03.10.01', 'm.d.y');
validateDateTime('10, 3, 2001', 'j, n, Y');
validateDateTime('20010310', 'Ymd');
validateDateTime('05-16-18, 10-03-01', 'h-i-s, j-m-y');
validateDateTime('Monday 8th of August 2005 03:12:46 PM', 'l jS \of F Y h:i:s A');
validateDateTime('Wed, 25 Sep 2013 15:28:57', 'D, d M Y H:i:s');
validateDateTime('17:03:18 is the time', 'H:m:s \i\s \t\h\e \t\i\m\e');
validateDateTime('17:16:18', 'H:i:s');

// These return false
validateDateTime('2001-03-10 17:16:18', 'Y-m-D H:i:s');
validateDateTime('2001', 'm');
validateDateTime('Mon', 'D-m-y');
validateDateTime('Mon', 'D-m-y');
validateDateTime('2001-13-04', 'Y-m-d');

【讨论】:

使用测试时,在if 内简单地返回truefalse,返回测试本身。 但是2018-3-24返回false,方法receive 2018-3-24,格式为apply时返回2018-03-24;如何通过两种方式返回 true?【参考方案8】:

我有这样的东西,即使使用 PHP,我也喜欢找到 功能性 解决方案。所以举个例子,@migli 给出的答案确实是一个很好的答案,非常灵活和优雅。

但它有一个问题:如果您需要验证大量相同格式的 DateTime 字符串怎么办?您将不得不在所有地方重复该格式,这违反了 DRY 原则。我们可以将格式放在一个常量中,但仍然必须将常量作为参数传递给每个函数调用。

但不要再害怕了!我们可以使用 currying 来拯救我们! PHP 不会让这项任务变得愉快,但仍然可以使用 PHP 实现柯里化:

<?php
function validateDateTime($format)

    return function($dateStr) use ($format) 
        $date = DateTime::createFromFormat($format, $dateStr);
        return $date && $date->format($format) === $dateStr;
    ;

那么,我们刚刚做了什么?基本上,我们将函数体包装在匿名中并返回这样的函数。我们可以这样调用验证函数:

validateDateTime('Y-m-d H:i:s')('2017-02-06 17:07:11'); // true

是的,差别不大……但真正的力量来自 部分应用函数,通过柯里化实现:

// Get a partially applied function
$validate = validateDateTime('Y-m-d H:i:s');

// Now you can use it everywhere, without repeating the format!
$validate('2017-02-06 17:09:31'); // true
$validate('1999-03-31 07:07:07'); // true
$validate('13-2-4 3:2:45'); // false

函数式编程 FTW!

【讨论】:

恕我直言的最佳答案(以更大的灵活性解决了 OP 的特定问题,并且与其他答案的代码量几乎相同) 恕我直言,这真是丑陋的编程,只需将您的值放在一个数组中并循环通过它们进行验证,但请不要这样做! 我很好奇@Tim,你能给我们举一个你的数组/循环验证的例子吗?【参考方案9】:

经过测试的正则表达式解决方案:

    function isValidDate($date)
    
            if (preg_match("/^(((((1[26]|2[048])00)|[12]\d([2468][048]|[13579][26]|0[48]))-((((0[13578]|1[02])-(0[1-9]|[12]\d|3[01]))|((0[469]|11)-(0[1-9]|[12]\d|30)))|(02-(0[1-9]|[12]\d))))|((([12]\d([02468][1235679]|[13579][01345789]))|((1[1345789]|2[1235679])00))-((((0[13578]|1[02])-(0[1-9]|[12]\d|3[01]))|((0[469]|11)-(0[1-9]|[12]\d|30)))|(02-(0[1-9]|1\d|2[0-8])))))$/", $date)) 
                    return $date;
            
            return null;
    

如果日期无效或者不是yyyy-mm-dd格式则返回null,否则返回日期。

【讨论】:

【参考方案10】:

检查给定日期是否有效的最简单方法可能是使用 strtotime 将其转换为 unixtime,将其格式化为给定日期的格式,然后进行比较:

function isValidDate($date) return date('Y-m-d', strtotime($date)) === $date;

当然你可以使用正则表达式来检查有效性,但是它会限制在给定的格式,每次你都必须编辑它以满足其他格式,而且它会超出要求。内置函数是(在大多数情况下)完成工作的最佳方式。

【讨论】:

我觉得这个答案质量很低,尤其是考虑到 已经 strtotime 答案。 这是最短的答案并且有效。说它质量低,有点苛刻。 @user4600953 - 这是最简单的方法。很多其他人都说要使用checkdate() - 但如果年份是任何值,我发现 checkdate 失败:2, 20, 202, 2020, 20201 - 全部返回 true。我同意你的解决方案!【参考方案11】:
    /**** date check is a recursive function. it's need 3 argument 
    MONTH,DAY,YEAR. ******/

    $always_valid_date = $this->date_check($month,$day,$year);

    private function date_check($month,$day,$year)

        /** checkdate() is a php function that check a date is valid 
        or not. if valid date it's return true else false.   **/

        $status = checkdate($month,$day,$year);

        if($status == true)

            $always_valid_date = $year . '-' . $month . '-' . $day;

            return $always_valid_date;

        else
            $day = ($day - 1);

            /**recursive call**/

            return $this->date_check($month,$day,$year);
        

    

【讨论】:

没有任何解释的代码不是很有用。【参考方案12】:

这个怎么样?

我们只是使用一个 try-catch 块。

$dateTime = 'an invalid datetime';

try 
    $dateTimeObject = new DateTime($dateTime);
 catch (Exception $exc) 
    echo 'Do something with an invalid DateTime';

这种方法不仅限于一种日期/时间格式,而且您不需要定义任何函数。

【讨论】:

这不适用于日期时间值 0000-00-00 00:00:00 @NaseeruddinVN '0000-00-00 00:00:00' 是一个有效的日期时间值。这只是第一个值。但是,日期时间对象的日期属性将是 '-0001-11-30 00:00:00'【参考方案13】:

试试这个:

$date = "2017-10-01";


function date_checker($input,$devider)
  $output = false;

  $input = explode($devider, $input);
  $year = $input[0];
  $month = $input[1];
  $day = $input[2];

  if (is_numeric($year) && is_numeric($month) && is_numeric($day)) 
    if (strlen($year) == 4 && strlen($month) == 2 && strlen($day) == 2) 
      $output = true;
    
  
  return $output;


if (date_checker($date, '-')) 
  echo "The function is working";
else 
  echo "The function isNOT working";

【讨论】:

【参考方案14】:
/*********************************************************************************
Returns TRUE if the input parameter is a valid date string in "YYYY-MM-DD" format (aka "mysql date format")
The date separator can be only the '-' character.
*********************************************************************************/
function isMysqlDate($yyyymmdd)

    return checkdate(substr($yyyymmdd, 5, 2), substr($yyyymmdd, 8), substr($yyyymmdd, 0, 4)) 
        && (substr($yyyymmdd, 4, 1) === '-') 
        && (substr($yyyymmdd, 7, 1) === '-');

【讨论】:

【参考方案15】:

恐怕大多数投票的解决方案 (https://***.com/a/19271434/3283279) 无法正常工作。第四个测试用例 (var_dump(validateDate('2012-2-25')); // false) 是错误的。日期是正确的,因为它对应于格式 - m 允许月份带或不带前导零(请参阅:http://php.net/manual/en/datetime.createfromformat.php)。因此,日期 2012-2-25 的格式为 Y-m-d,并且测试用例必须是 true 而不是 false。

我认为更好的解决方案是测试可能的错误如下:

function validateDate($date, $format = 'Y-m-d') 
    DateTime::createFromFormat($format, $date);
    $errors = DateTime::getLastErrors();

    return $errors['warning_count'] === 0 && $errors['error_count'] === 0;

【讨论】:

【参考方案16】:

使用 checkdate 函数验证:

$date = '2019-02-30';

$date_parts = explode( '-', $date );

if(checkdate( $date_parts[1], $date_parts[2], $date_parts[0] ))
    //date is valid
else
    //date is invalid

【讨论】:

检查日期的文档:w3schools.com/php/func_date_checkdate.asp【参考方案17】:

要添加到已接受的答案,您可以通过检查格式化日期是否为 instanceof DateTime 来进一步检查有效日期或 DateTime。

$date = DateTime::createFromFormat('Ymd', $value);
$is_datetime = ($date instanceof DateTime);
$is_valid_datetime_format = $is_datetime
  ? ($date->format('Ymd') === $value)
  : false;

if (!$is_datetime || !$is_valid_datetime_format) 
  // Not a valid date.
  return false;

这将捕获不是DateTime 的任何值,例如随机字符串或无效日期,例如20202020

【讨论】:

【参考方案18】:

试着告诉我它对我有用

$date = \DateTime::createFromFormat('d/m/Y', $dataRowValue);
if (!empty($date)) 
//Your logic
else
//Error

如果您传递任何 alpha 或 alphanumberic 值,它将返回空值

【讨论】:

以上是关于正确确定日期字符串是不是是该格式的有效日期的主要内容,如果未能解决你的问题,请参考以下文章

NSDateFormatter 仍在解析而不是格式不正确

Chrome返回字符串“FY 2000”的有效日期而不是无效日期[重复]

ORA-01843: 即使我的日期格式正确也不是有效月份

杭电oj 2005

php 验证(检查)日期格式是否正确

如何获取由 Carbon::parse() 解析日期时间字符串的格式说明符