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


184

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

J'utilise actuellement une expression régulière pour valider le format de la chaîne, ce qui fonctionne bien, mais je peux voir certains cas où cela pourrait être un format correct selon la chaîne mais en fait une date invalide. c'est-à 2013-13-01- dire , par exemple.

Existe-t-il un meilleur moyen en PHP de prendre une chaîne telle que 2013-13-01et de dire si c'est une date valide ou non pour le format yyyy-mm-dd?


Possible duplicata de validation de la date php
Vivek Athalye

2
La réponse ici est bien meilleure de toute façon.
Sebastien le

Réponses:


454

Vous pouvez utiliser la DateTimeclasse à cet effet:

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!


14
Si vous utilisez PHP 5.2.x, vous devez utiliser strtotimepour obtenir l'horodatage unix puis date('Y-m-d', $t)pour obtenir la date de la chaîne. Ensuite, vous les comparez comme cette réponse.
pedromanoel

2
@pedromanoel: pour l'entrée datetime standard, vous pouvez utiliser strtotime, mais pour les formats non standard qui strtotimene reconnaissent pas, vous aurez besoin d'une autre solution. Et pour la version 5.2 de php, le support s'est arrêté en janvier 2011, pour le support de la version 5.3 arrêté en août 2014.
Glavić

2
considérer cette datevar_dump( validateDate('2012-2-9'));
reignsly

4
La fonction fonctionne correctement. Il a renvoyé false car le format thr que vous avez spécifié était incorrect. Si vous souhaitez utiliser le jour et le mois sans zéros non significatifs, le format doit être 'Y-n-j'@reignsly.
Amal Murali

1
@ AntonyD'Andrea: non, cela ne fonctionnera pas sans cette partie. Car $dne sera pas faux en lui donnant la date, qui a survolé des parties, comme le 13ème mois (2013-13-01). Mais cela dépend vraiment de ce que vous voulez. Si vous avez besoin par exemple validateDate('2015-55-66')d'être valide, alors oui, il vous suffit de vérifier si $dc'est un objet ou non.
Glavić

81

Déterminer si une chaîne est une date

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

2
Cela valide toute une gamme de formats de date valides non seulement yyyy-mm-dd.
EWit

10
@MichelAyres c'est parce que php considère 2015-02-30comme une date valide car lorsque le jour indiqué est supérieur au nombre de jours du mois donné (ou négatif), php passe au mois suivant. Étant donné que la date est garantie au format, yyyy-mm-ddcela peut être corrigé en modifiant le retour en return (bool)strtotime($myDateString) && date("Y-m-d", strtotime($myDateString)) == $myDateString;.
elitechief21

2
Pourquoi est- (bool)strtotime('s')ce vrai?
Peon

cela renvoie également 1 checkIsAValidDate ("F");
Vaibhav Bhanushali

nous pouvons utiliser $myDateString = str_replace("/", '-', $myDateString);avant le retour si la chaîne de date contient des barres obliques (/) comme: - jj / mm / aaaa
Yashrajsinh Jadeja

37

Utilisez de manière simple avec la fonction prédéfinie de php:

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

Tester

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

1
Belle solution simple, a travaillé la première fois, merci :)
David Bell

Encore une fois, lors de l'utilisation d'un test, dans un ifpour retourner simplement trueou false, renvoyer le test lui-même.
Victor Schröder

4
Cela suppose qu'il y a au moins 3 éléments dans le tableau $ tempDate.
personne27

2
@ person27:return sizeof($tmpDate) == 3 && checkdate($tmpDate[1]...
neurino

@vineet - cela échoue. Si l'année est 2, 20, 202, 2020ou même si l'année est 20201- il retourne vrai à chaque fois.
rolinger

16

Déterminer si la chaîne est une date, même si la 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');

Lors de l'utilisation d'un test, à l'intérieur d'un ifpour retourner simplement trueou false, renvoyer le test lui-même.
Victor Schröder

Mais 2018-3-24 renvoie faux, la méthode reçoit 2018-3-24, lorsque le format est appliqué, retourne 2018-03-24; comment puis-je revenir vrai de deux manières?
Aquiles Perez

12

Cette option est non seulement simple mais accepte également presque tous les formats, bien qu'avec des formats non standard, elle puisse être boguée.

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

Cela aurait dû être la réponse acceptée! Beaucoup, beaucoup plus simple.
Webmaster G

2
Il est important de noter que cela ne fonctionnera pas avec un format britannique (d / m / Y) car cela supposera qu'il convertit l'américain (m / d / Y). Cela ne semblera fonctionner que si le jour est inférieur à 12!
Sylvester Saracevas

@galki - j'ai testé cela et il échoue certaines valeurs. Si $ date = '202-03-31', il renvoie vrai. Mais ce n'est pas une date valide. J'ai trouvé que si vous modifiez l'année en une année non valide, elle retourne toujours vrai.
rolinger

@rolinger étrange ... peut-être qu'il voit 202AD? Quelle est l'horodatage de l'année "strtotime"?
galki

@galki - pas certain, mais 202renvoie un nombre négatif - qui réussit toujours le test.
rolinger

10

Vous pouvez également analyser la date pour le mois, la date et l'année, puis vous pouvez utiliser la fonction PHP checkdate()que vous pouvez lire ici: http://php.net/manual/en/function.checkdate.php

Vous pouvez également 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';
    }

en cas de février (comme commenté par elitechief21) function isValidDate ($ date) {return preg_match ("/ ^ [0-9] {4} - (0 [1-9] | 1 [0-2]) - (0 [1-9] | [1-2] [0-9] | 3 [0-1]) $ / ", $ date) && date (" Ymd ", strtotime ($ date)) == $ date; }
abdulwadood

4
Cette solution est très mauvaise, car elle ne vérifie en aucun cas la validité de la date. Tout mois peut avoir 31 jours, février inclus. N'importe quelle année peut avoir le 29 février. Valider les dates à l'aide de RegExp exigerait quelque chose de beaucoup plus complexe, avec des références en arrière et des perspectives négatives.
Victor Schröder

9

La façon la plus simple de vérifier si une date donnée est valide en la convertissant probablement en unixtime en utilisant strtotime, en la formatant au format de la date donnée, puis en la comparant:

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 la validité, mais elle sera limitée au format donné, à chaque fois que vous devrez la modifier pour satisfaire un autre format, et elle sera également plus que nécessaire. Les fonctions intégrées sont le meilleur moyen (dans la plupart des cas) de réaliser des travaux.


1
Je pense que cette réponse est de qualité médiocre , d'autant plus qu'il existe déjà des réponses strtotime.
GrumpyCrouton

4
C'est la réponse la plus courte et cela fonctionne. C'est un peu dur de dire que c'est de mauvaise qualité.
Tim Rogers

@ user4600953 - c'est le plus simple qui fonctionne. Beaucoup d'autres disent d'utiliser checkdate()- mais je trouve que la date de vérification échoue si l'année est une valeur quelconque: 2, 20, 202, 2020, 20201- tous retournent vrai. Je vais avec votre solution!
rolinger

7

En accord avec la réponse de cl-sah, mais ça 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

Vous aurez besoin de tester si count($tempDate) === 3bien
VDarricau

@VDarricau non vous ne le faites pas, checkdate bombardera s'ils sont manquants, vous pouvez écrire isset () pour chacun d'entre eux mais je supprimerais simplement les avertissements
M. Heelis le

7

J'ai ce truc qui, 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 cela pose un problème: que se passe-t-il si vous devez valider un grand nombre de chaînes DateTime avec le même format? Vous auriez à répéter le format partout, ce qui va à l'encontre du principe DRY . Nous pourrions mettre le format dans une constante, mais nous devrons quand même passer la constante en argument à chaque appel de fonction.

Mais n'ayez plus peur! Nous pouvons utiliser le curry à notre secours! PHP ne rend pas cette tâche agréable, mais il est toujours possible d'implémenter le curry 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 que nous venons de faire? Fondamentalement, nous avons enveloppé le corps de la fonction dans un anonyme et renvoyé une telle fonction à la place. 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 la vraie puissance vient de la fonction partiellement appliquée , rendue possible par le curry:

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


2
La meilleure réponse par un glissement de terrain IMHO (résout le problème spécifique de l'OP avec une plus grande flexibilité et à peu près la même quantité de code que le reste des réponses)
StubbornShowaGuy

IMHO c'est une programmation vraiment moche, il suffit de mettre vos valeurs dans un tableau et de les parcourir pour valider, mais ne faites pas cela!
Tim

Je suis curieux de @Tim, pouvez-vous nous donner un exemple de la validation de votre tableau / boucle?
Victor Schröder

5

J'ai peur 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 faux. La date est correcte, car elle correspond au format - le m autorise un mois avec ou sans zéro non significatif (voir: http://php.net/manual/en/datetime.createfromformat.php ). Par conséquent, une date 2012-2-25 est au format Ymd et le cas de test doit être vrai et non faux.

Je pense que la meilleure solution consiste à tester les erreurs possibles 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;
}

3

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 pas besoin de définir de fonction.


cela ne fonctionnera pas pour la valeur datetime 0000-00-00 00:00:00
Naseeruddin VN

@NaseeruddinVN '0000-00-00 00:00:00'est une valeur datetime valide. C'est juste la première valeur. Cependant, la propriété date de l'objet datetime sera '-0001-11-30 00:00:00'.
Julian

1

Solution Regex testée:

    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 renverra null si la date n'est pas valide ou n'est pas au format aaaa-mm-jj, sinon il renverra la date.



0
/*********************************************************************************
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) === '-');
}

-1
    /**** date check is a recursive function. it's need 3 argument 
    MONTH,DAY,YEAR. ******/

    $always_valid_date = $this->date_check($month,$day,$year);

    private function date_check($month,$day,$year){

        /** checkdate() is a php function that check a date is valid 
        or not. if valid date it's return true else false.   **/

        $status = checkdate($month,$day,$year);

        if($status == true){

            $always_valid_date = $year . '-' . $month . '-' . $day;

            return $always_valid_date;

        }else{
            $day = ($day - 1);

            /**recursive call**/

            return $this->date_check($month,$day,$year);
        }

    }

1
Le code sans aucune explication n'est pas très utile.
Gert Arnold

-2

Essayez ceci:

$date = "2017-10-01";


function date_checker($input,$devider){
  $output = false;

  $input = explode($devider, $input);
  $year = $input[0];
  $month = $input[1];
  $day = $input[2];

  if (is_numeric($year) && is_numeric($month) && is_numeric($day)) {
    if (strlen($year) == 4 && strlen($month) == 2 && strlen($day) == 2) {
      $output = true;
    }
  }
  return $output;
}

if (date_checker($date, '-')) {
  echo "The function is working";
}else {
  echo "The function isNOT working";
}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.