如何检查字符串是不是是有效的 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)
这应该只选择有效的DATETIME
s,也应该相应地适用于DATE
和TIME
,但没有经过测试...
我没有找到关于转换失败时 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的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Python 中检查字符串是不是是有效的 JSON?