views:

335

answers:

4

When I try to put a value into a DATE field which is invalid, MySQL seems to use 0000-00-00 instead. Is there a way I can do this "check" without updating a DATE field? And to do it from for example PHP?

Like, is there a way I can query the MySQL server and ask "Hey, is this DATE, TIME or DATETIME valid to you?"

Or is there maybe an even better way of doing it?

+1  A: 

If you choose a server mode for the MySQL server that doesn't allow invalid date values a query containing such a malformed date representation will cause an error instead of (silently) assuming 0000-00-00
see http://dev.mysql.com/doc/refman/5.0/en/server-sql-mode.html

e.g.

$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";
}

prints

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 [...]
VolkerK
Good to know! Will look into setting that mode. With this I would have to actually try and then catch the exception though. Is there a way I can check it before I run the insert or update?
Svish
None that I know of. But does it matter whether a (fictional) function mysql\_check\_date() returns false or the execution of the query fails (with a specific error code)?
VolkerK
When I need it to validate user input, then yes, kind of. Especially if you want to do the check "client-side" using AJAX or something before submit.
Svish
A: 

Use this function in php to check for a valid date:

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

Or as @VolkerK said if an invalid date is inserted into the database it will be stored as 0000-00-00 so you could also do:

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

fire
but this function returns true with '2010-32-56'
Osman Üngür
Yeah, that will weed out the dates in the wrong format, but doesn't take care of invalid dates. Is already using this for a pre-check though, except I use `\d` instead of `[0-9]`. And the parenthesis isn't needed AFAIK: `/^\d{4}-\d{2}-\d{2}$/`
Svish
A: 

You could parse the date according to the format you want to use and then call checkdate to test if it's a valid date. Make sure you read the comments on http://php.net/manual/en/function.checkdate.php.

wimvds
A: 

You could just use a 'constant' query, without using temporary tables and test fields:

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