web-dev-qa-db-fra.com

MySQL: Comment vérifier si une chaîne est une DATE, TIME ou DATETIME valide

Lorsque j'essaie de définir une valeur non valide dans un champ DATE, MySQL semble utiliser plutôt 0000-00-00. Est-il possible de faire cette "vérification" sans mettre à jour un champ DATE? Et pour le faire par exemple de PHP?

Par exemple, puis-je interroger le serveur MySQL et demander "Hé, cette date, cette heure ou cette date est-elle valide?"

Ou y a-t-il peut-être une meilleure façon de le faire?

18
Svish

Si vous choisissez un mode de serveur pour le serveur MySQL qui n'autorise pas les valeurs de date non valides, une requête contenant une telle représentation de date malformée provoquera une erreur au lieu de (en silence) en supposant que 0000-00-00
voir http://dev.mysql.com/doc/refman/5.0/en/server-sql-mode.html

par exemple.

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

empreintes

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 [...]
2
VolkerK

J'utilise cette syntaxe dans mon application et ça marche comme un charme!

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

Mon système est Win7x64 avec PHP 5.5 et MySQL 5.6.16.

6
Abbas

Vous pouvez analyser la date en fonction du format que vous souhaitez utiliser, puis appeler Checkdate pour vérifier s’il s’agit d’une date valide. Assurez-vous de lire les commentaires sur http://php.net/manual/en/function.checkdate.php .

6
wimvds

Puisque la question dit MySQL , voici une solution MySQL

Il est très difficile de vérifier si un champ est une date en raison de tous les formats de date possibles qu'il faudrait prendre en compte. MAIS si vous savez que les formats de date de champ sont l’un de ceux-ci: 

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

Ce code vous aidera:

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

Fondamentalement : 

  • la première condition vous indique si est une date, mais n'exclut malheureusement pas les nombres (ex: DATE(STR_TO_DATE(**1**, '%Y-%m-%d')) = '2001-00-00'
  • le second garantit que les nombres sont exclus, ce qui vous laisse des dates qui suivent les formats ci-dessus.

Si count(*) est >0, alors c'est une date, s'il s'agit de 0, c'est autre chose.

Remarque Cette méthode fonctionne pour les chaînes de tout format de date, à condition de savoir à l'avance quel format elles suivent (ce que je sais, ce n'est pas toujours le cas mais reste utile). Il suffit de remplacer le format a priori dans la requête

3
BassMHL

Vous pouvez simplement utiliser une requête 'constante', sans utiliser de tables temporaires ni de champs de test:

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

Je fais ça:

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

}
1
Mubashar Abbas

Pour vérifier si une valeur est une date, vous pouvez utiliser day(dateToCheck) = 0

DATETIME - en 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)

Ceci ne devrait sélectionner que les DATETIMEs valides, ainsi que devrait être applicable à DATE et TIME en conséquence, mais pas testé ...

Je n'ai trouvé aucune documentation sur la valeur de retour CAST() lors d'un échec de conversion, mais la documentation couvre un cas particulier - un échec possible - qui renvoie NULL:

Pour la conversion d'une chaîne de date «zéro» en date, CONVERT() et CAST() renvoie NULL et génère un avertissement lorsque le NO_ZERO_DATE mode SQL est activée.

En outre, d'après mes tests, semble que CAST() se comporte de la même manière sur any convert failure - renvoie NULL et génère un avertissement.

_ {J'ai effectivement testé cela sur MariaDB 10.0.30

0
jave.web

Peut-être devez-vous créer une base de données avec le moteur BLACKHOLE, lisez ici . Et vérifiez l'exception levée par 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());
    }
}
0
krisanalfa

Utilisez cette fonction en php pour vérifier une date valide:

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

Ou, comme @VolkerK l'a dit, si une date non valide est insérée dans la base de données, elle sera stockée sous le nom 0000-00-00.

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

0
fire

Une simple fonction PHP qui validera les types de données MySQL "date" et "date/heure" Est dans l'exemple de code qui suit (chk_MySQL_Datetime). Il valide en utilisant createFromFormat () pour Créer un objet Date pour la date/date heure si cela échoue, alors la date/date/heure .__ n'est pas valide. Si un objet Date est créé, une chaîne formatée créée avec Date_format () et comparée à la date/heure . Si les chaînes sont égales, la date/date/heure est valide . Si différent de la date/Les date/heure ne sont pas valides. Cette comparaison est nécessaire car createFromFormat () acceptera le 2009/02/29 09:85 comme date/heure valide Mais pas MySQL.

Le code suivant inclut un exemple/cas de test qui montre l'utilisation et les tests sur une base de données MySQL . Pour utiliser cet exemple, vous devrez remplacer $ database-> domysql_query () par un appel à une base de données. Les résultats des échos sont inclus sous forme de commentaires immédiatement après les instructions 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
?>
0
user3342806