如何检查字符串是不是是有效的 DATE、TIME 或 DATETIME

Posted

技术标签:

【中文标题】如何检查字符串是不是是有效的 DATE、TIME 或 DATETIME【英文标题】:How to check if a string is a valid DATE, TIME or DATETIME如何检查字符串是否是有效的 DATE、TIME 或 DATETIME 【发布时间】:2011-02-11 00:34:13 【问题描述】:

当我尝试将值放入无效的 DATE 字段时,mysql 似乎使用 0000-00-00 代替。有没有一种方法可以在不更新 DATE 字段的情况下进行此“检查”?并通过例如 php 来做到这一点?

例如,有没有一种方法可以查询 MySQL 服务器并询问“嘿,这个 DATE、TIME 或 DATETIME 对你有效吗?”

或者有没有更好的方法?

【问题讨论】:

我真的很讨厌如果你通过 php 在 mysql 的日期列中插入任何无效值,你会得到一个 '0000-00-00'!它应该失败(首选)、将其保留为 null 或将其设置为字段的声明默认值。 我也这样做了,但认为你可以改变这一点。只需要开启严格模式什么的:dev.mysql.com/doc/refman/5.5/en/… 实际上就像@VolkerK 的回答一样,***.com/a/2690242/39321 :) 您可以随时将数据复制到测试系统并试用 ;) 是的,启用严格模式,它还会发现一些其他问题。 【参考方案1】:

我在我的应用程序中使用了这种语法,它的工作就像魅力一样!

SELECT DATE('2013-09-31') AS valid;

我的系统是 Win7x64,PHP 5.5 和 MySQL 5.6.16

【讨论】:

谢谢。对我来说效果很好!【参考方案2】:

您可以根据要使用的格式解析日期,然后调用 checkdate 来测试它是否是有效日期。请务必阅读http://php.net/manual/en/function.checkdate.php 上的 cmets。

【讨论】:

【参考方案3】:

由于问题是 MySQL,这里有一个 MySQL 解决方案:

验证字段是否为日期非常困难,因为需要考虑所有不同的可能日期格式。但是,如果您知道字段日期格式是其中之一:

'yyyy-mm-dd'
'yyyy-mm-dd hh:mm:ss'
'yyyy-mm-dd whatever'

此代码将帮助您:

 SELECT count(*) FROM `table` 
 WHERE DATE(STR_TO_DATE(`column`, '%Y-%m-%d')) IS NOT NULL
 AND `column` NOT REGEXP '^[0-9\.]+$'

基本上:

第一个条件告诉您是否是日期,但不幸的是不排除数字(例如:DATE(STR_TO_DATE(**1**, '%Y-%m-%d')) = '2001-00-00' 第二个确保数字被排除在外,这样您就只能得到符合上述格式的日期。

如果count(*)>0,那么它就是一个日期,如果它是0,它就是别的东西。

注意 此方法适用于任何日期格式的字符串,只要您事先知道它们遵循的格式(我知道并非总是如此,但仍然有用)。只需替换查询中的格式a priori

【讨论】:

【参考方案4】:

您可以只使用“常量”查询,而不使用临时表和测试字段:

mysql> select day('2010-02-31 00:00:00');
+----------------------------+
| day('2010-02-31 00:00:00') |
+----------------------------+
|                       NULL | 
+----------------------------+

【讨论】:

奇怪的是,这似乎不起作用。我遇到了一个服务器,其中更新给出了错误 1292:Incorrect datetime value: '2012-09-13T17:58:23+02:00',但 select day('2012-09-13T17:58:23+02:00') 给出了 13。 如果字段的值为 '0',则此方法不起作用,例如 day('0')=0。您应该添加 day(column) 不为 null 并且 day(column) 0。请参阅我的另一种方法的答案【参考方案5】:

如果您为 MySQL 服务器选择不允许无效日期值的服务器模式,则包含这种格式错误的日期表示的查询将导致错误,而不是(默默地)假设 0000-00-00 见http://dev.mysql.com/doc/refman/5.0/en/server-sql-mode.html

例如

$pdo = new PDO('mysql:host=localhost;dbname=test', 'localonly', 'localonly'); 
$pdo->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );

$pdo->exec('CREATE TEMPORARY TABLE foo (id int auto_increment, d datetime, primary key(id))');

$query = "INSERT INTO foo (d) VALUES ('2010-02-31 12:15:18')";
foreach( array('ALLOW_INVALID_DATES', 'STRICT_ALL_TABLES') as $mode ) 
  echo $mode, ": "; flush();
  $pdo->exec("SET SESSION sql_mode='$mode'");
  $pdo->exec($query);
  echo "Ok.\n";

打印

ALLOW_INVALID_DATES: Ok.
STRICT_ALL_TABLES: 
Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[22007]: Invalid datetime format: 1292 Incorrect datetime value: '2010-02-31 12:15:18' for column 'd' at row 1' in [...]

【讨论】:

很高兴知道!将研究设置该模式。有了这个,我将不得不实际尝试然后捕获异常。有没有办法在运行插入或更新之前检查它? 我不知道。但是(虚构的)函数 mysql_check_date() 返回 false 或查询的执行失败(带有特定的错误代码)是否重要? 当我需要它来验证用户输入时,是的,有点。特别是如果您想在提交之前使用 AJAX 或其他方式检查“客户端”。【参考方案6】:

SELECT WEEK(col) IS NOT NULL AS valid;

或以下之一:

SELECT DAYNAME(col) IS NOT NULL AS valid;
SELECT TO_DAYS(col) IS NOT NULL AS valid;
SELECT TO_SECONDS(col) IS NOT NULL AS valid;
SELECT WEEKDAY(col) IS NOT NULL AS valid;
SELECT WEEKOFYEAR(col) IS NOT NULL AS valid;
SELECT YEARWEEK(col) IS NOT NULL AS valid;

【讨论】:

【参考方案7】:

要检查一个值是否是一个日期,您可以使用 day(dateToCheck) = 0

【讨论】:

【参考方案8】:

我这样做:

if(strtotime(trim($str)) 
    // persist trim($str) in db.        


【讨论】:

【参考方案9】:

在php中使用这个函数来检查一个有效的日期:

function valid_date($date) 
    return (preg_match("/^([0-9]4)-([0-9]2)-([0-9]2)$/", $date));

或者正如@VolkerK所说,如果将无效日期插入数据库,它将被存储为 0000-00-00 所以你也可以这样做:

SELECT * FROM table WHERE date_field > '0000-00-00'

【讨论】:

但是这个函数返回 true 与 '2010-32-56' 是的,这会清除格式错误的日期,但不会处理无效日期。虽然已经在使用它进行预检查,但我使用\d 而不是[0-9]。并且不需要括号 AFAIK:/^\d4-\d2-\d2$/【参考方案10】:

一个简单的 PHP 函数,将验证“日期”和“日期时间”的 MySQL 数据类型 在后面的代码示例中 (chk_MySQL_Datetime)。它通过使用 createFromFormat() 来验证 如果失败,则为日期/日期时间创建一个 Date 对象,然后创建日期/日期时间 是无效的。如果创建了日期对象,则使用创建的格式化字符串 date_format() 并与日期/时间进行比较。 如果字符串相等,则日期/日期时间有效。 如果不相等,则日期/日期时间无效。这个比较 是必要的,因为 createFromFormat() 将接受 2009/02/29 09:85 作为有效的日期时间 但 MySQL 不会。

以下代码包含一个示例/测试用例,显示了对 MySQL 数据库的使用和测试。 要使用该示例,您必须将 $database->domysql_query() 替换为对数据库的调用。 echo 的输出作为 cmets 包含在 echo 语句之后。

<?php
/**
 * Returns false if MySQL date or datetime value would be stored as
 * 0000-00-00  or 0000-00-00 00:00:00.
 * @param string $fmt - createFromFormat format of MySQL datetime value
 * to be tested. see http://www.php.net/manual/en/datetime.createfromformat.php
 * @param string $datetime MySQL datetime value
 * to be tested.
 * @return DateTime object formatted according to $fmt or FALSE if not
 * valid MySQL datetime value (would be inserted into the database
 * 0000-00-00 00:00:00);
 */
function chk_MySQL_Datetime($fmt, $datetime) 
    global $fmtdatetime;  // for example only
    $ckdate = DateTime::createFromFormat($fmt, $datetime);
    if ($ckdate !== FALSE) 
        $fmtdatetime = date_format($ckdate, $fmt);
        if ($fmtdatetime != $datetime) 
            $ckdate = FALSE;
        
    

    return $ckdate;

/*  Example/test of  chk_MySQL_Datetime */
/**
 * Creates table datetimetest if it doesn't exist
 * and insert a record in primary index of type datetime
 * then select record inserted and return result as a formated string.
 * @global type $database - addressibility to database functions
 * @global type $mysqlenum - MySql errornumber of last operation
 * @global type $fmtdatetime - $datetime formatted by date_format
 * @param type $datetime - datetime vale to be set
 * @return string of what was inserted
 */
function insert_in_table($datetime) 
    global $database, $mysqlenum, $fmtdatetime;
    $sql = "CREATE TABLE IF NOT EXISTS `datetimetest` (
  `MySQL_datetime` datetime NOT NULL COMMENT 'datetime created by MySQL',
  `in_datetime` varchar(90) NOT NULL COMMENT 'date time string',
  `fmtdatetime` varchar(90) NOT NULL COMMENT 'Output of createFromFormat',
  PRIMARY KEY (`MySQL_datetime`)
) ;";
    $result = $database->domysql_query($sql, $database->connection, true);

    $sql = "DELETE FROM `datetimetest`  WHERE MySQL_datetime='$datetime' OR `MySQL_datetime` = '0000-00-00 00:00:00'; ";
    $result = $database->domysql_query($sql, $database->connection, false);
    $sql = "INSERT INTO `datetimetest` (MySQL_datetime, in_datetime, fmtdatetime)
       VALUES ('$datetime', '$datetime', '$fmtdatetime')";
    $result = $database->domysql_query($sql, $database->connection, false);
    $sql = "SELECT * FROM `datetimetest`  WHERE MySQL_datetime='$datetime' OR `MySQL_datetime` = '0000-00-00 00:00:00'; ";
    $result = $database->domysql_query($sql, $database->connection, false);
    $contxa = mysql_fetch_assoc($result);

    $ret = " Inserted datetime = " . $contxa['in_datetime'] . "," .
            " MySQL stored " . $contxa['MySQL_datetime'] .
            ", fmtdatetime = " . $contxa['fmtdatetime'] . "<br>";
    return $ret;


        global $fmtdatetime;
        echo('<br>');
        $format = 'Y-m-d';
        $datetime = '2009-02-15'; // valid date
        $date = chk_MySQL_Datetime($format, $datetime);
        echo "Format: $format; datetime is " . ($date ? 'valid' : 'invalid' ) . " Expected $datetime is " . $fmtdatetime . "<br>";
 //echo output = Format: Y-m-d; datetime is valid Expected 2009-02-15 is 2009-02-15

        $result = insert_in_table($datetime);
        echo $result . "<br>";
 //echo output = Inserted datetime = 2009-02-15, MySQL stored 2009-02-15 00:00:00, fmtdatetime = 2009-02-15

        $datetime = '2009-02-29'; //invalid date
        $date = chk_MySQL_Datetime($format, $datetime);
        echo "Format: $format; datetime is " . ($date ? 'valid' : 'invalid' ) . " Expected $datetime is " . $fmtdatetime . "<br>";
 //echo output = Format: Y-m-d; datetime is invalid Expected 2009-02-29 is 2009-03-01

        $result = insert_in_table($datetime);
        echo $result . "<br>";
 //echo output =  Inserted datetime = 2009-02-29, MySQL stored 0000-00-00 00:00:00, fmtdatetime = 2009-03-01

        $format = 'Y-m-d H:i';
        $datetime = '2009-02-15 14:20';
        $date = chk_MySQL_Datetime($format, $datetime);
        echo "Format: $format; datetime is " . ($date ? 'valid' : 'invalid' ) . " Expected $datetime is " . $fmtdatetime . "<br>";
//echo output = Format: Y-m-d H:i; datetime is valid Expected 2009-02-15 14:20 is 2009-02-15 14:20

        $result = insert_in_table($datetime);
        echo $result . "<br>";
//echo output = Inserted datetime = 2009-02-15 14:20, MySQL stored 2009-02-15 14:20:00, fmtdatetime = 2009-02-15 14:20

        $datetime = '2009-02-15 14:63';  // invalid time
        $date = chk_MySQL_Datetime($format, $datetime);
        echo "Format: $format; datetime is " . ($date ? 'valid' : 'invalid' ) . " Expected $datetime is " . $fmtdatetime . "<br>";
//echo output = Format: Y-m-d H:i; datetime is invalid Expected 2009-02-15 14:63 is 2009-02-15 15:03

        $result = insert_in_table($datetime);
        echo $result . "<br>";
 //echo output = Inserted datetime = 2009-02-15 14:63, MySQL stored 0000-00-00 00:00:00, fmtdatetime = 2009-02-15 15:03

        $datetime = 'x-02-15 14:59';  // invalid time
        $date = chk_MySQL_Datetime($format, $datetime);
        echo "Format: $format; datetime is " . ($date ? 'valid' : 'invalid' ) . " Expected $datetime is " . $fmtdatetime . "<br>";
 //echo output = Format: Y-m-d H:i; datetime is invalid Expected x-02-15 14:59 is 2009-02-15 15:03

        $result = insert_in_table($datetime);
        echo $result . "<br>";
//echo output =  Inserted datetime = x-02-15 14:59, MySQL stored 0000-00-00 00:00:00, fmtdatetime = 2009-02-15 15:03
?>

【讨论】:

【参考方案11】:

也许您必须使用BLACKHOLE 引擎创建一个数据库,请阅读here。并检查 PDOException 抛出的异常。

$dbh = new PDO('mysql:host=localhost;dbname=test', 'username', 'p@s5W0Rd!!!', array(PDO::ATTR_PERSISTENT => true));

// CREATE DATABASE test;
// CREATE TABLE test.foo ( bar DATETIME ) ENGINE=BLACKHOLE;

try 
    $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

    $dbh->beginTransaction();

    $dateTime = new DateTime();
    $dateTime = $dateTime->format('c');
    $dbh->exec("INSERT INTO foo (bar) VALUES ('".$dateTime."')");
    $dbh->commit();
 catch (PDOException $e) 
    $errorInfo = $dbh->errorInfo();

    if ($e->getCode() === '22007'
        and $dbh->errorCode() === '22007'
        and $errorInfo[0] === '22007'
        and preg_match('/^incorrect datetime/', strtolower($errorInfo[2])) === 1) 

        throw new Exception($errorInfo[2], (int) $e->getCode());
    

【讨论】:

【参考方案12】:

日期时间 - 在 SQL 中

SELECT your_unreliable_datetime_column, CAST(your_unreliable_datetime_column as DATETIME)
FROM some_cool_table
WHERE
CAST(your_unreliable_datetime_column as DATETIME) IS NOT NULL
AND
your_unreliable_datetime_column = CAST(your_unreliable_datetime_column as DATETIME)

这应该只选择有效的DATETIMEs,也应该相应地适用于DATETIME,但没有经过测试...

我没有找到关于转换失败时 CAST() 返回值的任何文档,但 documentation covers a special case - 可能失败 - 返回 NULL

用于将“零”日期字符串转换为日期,CONVERT()CAST() 返回NULL 并在NO_ZERO_DATE SQL 模式为 已启用。

此外,根据我的测试,似乎CAST()任何 转换失败时表现相同 - 返回NULL 并生成警告。

我实际上在MariaDB 10.0.30上测试过这个

【讨论】:

【参考方案13】:

尝试使用这个... WHERE DATE_FORMAT(DATE('$value'), '%Y-%m-%d') = '$value'

使用 Perl 时,$sth->如果失败,rows 将返回零

while $sth->如果成功,rows 将返回非零

【讨论】:

【参考方案14】:

它应该可以解决 MySQL 中的问题。

对于纯 DATE 和 TIME 场景(使用 DATETIME 值,您可以按原样进行) - 只需将初始值与任何 TIME 或 DATE 字符串值相匹配以匹配您的 DB DATETIME 格式(例如 CONCAT( date_value, " 00:00 :00") 或 CONCAT("2021-12-31 ", time_value) ) - 作为此示例中的变量应该采用 DATETIME 格式。

# declare variables
SET @invalid_date:='2021-02-30 25:64:64', @valid_date:='2021-02-28 04:01:01';

# check valid DATE scenario: invalid_date -> NULL; valid_date -> NOT NULL - correct value
SELECT DATE( @invalid_date );
SELECT DATE( @valid_date );

# check valid TIME scenario: invalid_date -> NULL; valid_date -> NOT NULL - correct value
SELECT TIME( @invalid_date );
SELECT TIME( @valid_date );

# check valid DATETIME scenario: invalid_date -> NULL; valid_date -> NOT NULL - correct value
SELECT CAST( @invalid_date AS DATETIME );
SELECT CAST( @valid_date AS DATETIME );

# purge variables
SET @invalid_date:= NULL, @valid_date:=NULL;

享受吧。

【讨论】:

以上是关于如何检查字符串是不是是有效的 DATE、TIME 或 DATETIME的主要内容,如果未能解决你的问题,请参考以下文章

接收字符串并使用 date-fns 验证它是不是是有效日期

如何检查 DST(夏令时)是不是有效,如果有效,偏移量?

如何在 Python 中检查字符串是不是是有效的 JSON?

如何检查字符串是不是是android中的有效电子邮件? [复制]

如何检查字符串是不是是有效的 XML 元素名称?

如何检查字符串是不是是有效的十六进制颜色表示?