web-dev-qa-db-fra.com

Déterminer correctement si la chaîne de date est une date valide dans ce format

Je reçois une chaîne de date d'une API, qui est au format yyyy-mm-dd.

J'utilise actuellement une expression rationnelle pour valider le format de chaîne, ce qui fonctionne bien, mais je peux voir quelques cas où il pourrait s'agir d'un format correct en fonction de la chaîne, mais en réalité d'une date non valide. c'est-à-dire 2013-13-01, par exemple.

Existe-t-il un meilleur moyen dans PHP de prendre une chaîne telle que 2013-13-01 et d'indiquer s'il s'agit d'une date valide ou non pour le format yyyy-mm-dd?

138
Marty Wallace

Vous pouvez utiliser DateTime class à cette fin:

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

[Fonction tirée de cette réponse . Aussi sur php.net . Initialement écrit par Glavić .


Cas de test:

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

Démo!

365
Amal Murali

Déterminer si une chaîne est une date

function checkIsAValidDate($myDateString){
    return (bool)strtotime($myDateString);
}
64
arsh

Utilisez de manière simple avec la fonction php prebuilt:

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

Test

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

Détermine si chaîne est une date, même si chaîne est un format non standard

(strtotime n'accepte aucun format personnalisé)

<?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');
14
migli

Cette option est non seulement simple, mais accepte également presque tous les formats, même si elle peut être buggée avec des formats non standard.

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

Vous pouvez également analyser la date pour la date du mois et de l'année, puis utiliser la fonction PHP checkdate() à laquelle vous pouvez accéder ici: http://php.net/manual/en/function.checkdate.php

Vous pouvez aussi essayer celui-ci:

$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';
    }
9
Suvash sarker

Conforme à la réponse de cl-sah, mais cela sonne mieux, plus court ...

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

Tester

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

J'ai cette chose que, même avec PHP, j'aime trouver des solutions fonctionnelles . Ainsi, par exemple, la réponse donnée par @migli est vraiment bonne, très flexible et élégante.

Mais il y a un problème: que se passe-t-il si vous devez valider beaucoup de chaînes DateTime avec le même format? Il faudrait répéter le format un peu partout, ce qui va à l’encontre du principeSEC. Nous pourrions mettre le format dans une constante, mais il faudrait quand même passer la constante comme argument à chaque appel de fonction.

Mais ne crains plus! Nous pouvons utiliser currying à notre secours! PHP ne rend pas cette tâche agréable, mais il est toujours possible d'implémenter currying avec PHP:

<?php
function validateDateTime($format)
{
    return function($dateStr) use ($format) {
        $date = DateTime::createFromFormat($format, $dateStr);
        return $date && $date->format($format) === $dateStr;
    };
}

Alors, qu'est-ce qu'on vient de faire? Fondamentalement, nous avons enveloppé le corps de la fonction dans un fichier anonyme et avons renvoyé cette fonction. Nous pouvons appeler la fonction de validation comme ceci:

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

Ouais, pas une grande différence ... mais le vrai pouvoir vient de la fonction partiellement appliquée , rendue possible par currying:

// 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

Programmation fonctionnelle FTW!

6
Victor Schröder

Celui-ci, ça va?

Nous utilisons simplement un bloc try-catch. 

$dateTime = 'an invalid datetime';

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

Cette approche ne se limite pas à un seul format de date/heure et vous n'avez besoin de définir aucune fonction. 

3
Julian

Le moyen le plus simple de vérifier si la date donnée est valide est probablement de le convertir en unixtime à l'aide de strtotime, de le formater au format de la date donnée, puis de le comparer:

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

Bien sûr, vous pouvez utiliser une expression régulière pour vérifier sa validité, mais elle sera limitée à un format donné, chaque fois que vous devrez l'éditer pour satisfaire un autre format, et ce sera plus que nécessaire. Les fonctions intégrées constituent le meilleur moyen (dans la plupart des cas) d’obtenir des emplois.

2
Nurlan Alekberov

Solution testée Regex:

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

Cela retournera null si la date n'est pas valide ou s'il ne s'agit pas du format aaaa-mm-jj, sinon la date sera retournée.

1
Akumaburn

Valider avec checkdate function:

$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
}
0
Prince Ahmed

Je crains que la solution la plus votée ( https://stackoverflow.com/a/19271434/3283279 ) ne fonctionne pas correctement. Le quatrième cas de test (var_dump (validateDate ('2012-2-25')); // false) est incorrect. La date est correcte car elle correspond au format - le m permet un mois avec ou sans zéro (voir: http://php.net/manual/fr/datetime .createfromformat.php ). Par conséquent, une date 2012-2-25_ est au format Y-m-d_ et le scénario de test doit être vrai, pas faux.

Je crois que la meilleure solution consiste à tester l'erreur possible comme suit:

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

    return $errors['warning_count'] === 0 && $errors['error_count'] === 0;
}
0
Barvajz
/*********************************************************************************
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) === '-');
}
0
Marco Demaio