Determine correctamente si la cadena de fecha es una fecha válida en ese formato

184

Recibo una cadena de fecha de una API y está formateada como yyyy-mm-dd.

Actualmente estoy usando una expresión regular para validar el formato de cadena, que funciona bien, pero puedo ver algunos casos en los que podría ser un formato correcto de acuerdo con la cadena pero en realidad una fecha no válida. es decir 2013-13-01, por ejemplo.

¿Hay una mejor manera en PHP para tomar una cadena como 2013-13-01y decir si es una fecha válida o no para el formato yyyy-mm-dd?

Marty Wallace
fuente
Posible duplicado de la validación de la fecha
Vivek Athalye
2
La respuesta aquí es mucho mejor de todos modos.
Sebastien el

Respuestas:

454

Puede usar la DateTimeclase para este propósito:

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

[ Función tomada de esta respuesta . También en php.net . Originalmente escrito por Glavić . ]


Casos de prueba:

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

¡Manifestación!

Amal Murali
fuente
14
Si está usando PHP 5.2.x, debe usar strtotimepara obtener la marca de tiempo de Unix y luego date('Y-m-d', $t)obtener la fecha de la cadena. Luego los comparas como esta respuesta.
pedromanoel
2
@pedromanoel: para entrada de fecha y hora estándar que puede usar strtotime, pero para formatos no estándar que strtotimeno reconoce, necesitará alguna otra solución. Y para el soporte de la versión 5.2 de php se detuvo en enero de 2011, para el soporte de 5.3 se detuvo en agosto de 2014.
Glavić
2
considere esta fechavar_dump( validateDate('2012-2-9'));
reinantemente
44
La función funciona correctamente. Se devolvió falso porque el formato thr que especificó era incorrecto. Si desea usar día y mes sin ceros a la izquierda, entonces el formato debe ser 'Y-n-j', @reignsly.
Amal Murali
1
@ AntonyD'Andrea: no, no funcionará sin esa parte. Porque $dno será falso si le das la fecha, que ha desbordado partes, como el 13 ° mes (2013-13-01). Pero realmente depende de lo que quieras. Si necesita, por ejemplo, validateDate('2015-55-66')ser válido, entonces sí, solo necesita verificar si $des objeto o no.
Glavić
81

Determinar si alguna cadena es una fecha

function checkIsAValidDate($myDateString){
    return (bool)strtotime($myDateString);
}
arsh
fuente
2
Esto valida toda una gama de formatos de fecha válidos, no solo yyyy-mm-dd.
EWit
10
@MichelAyres esto se debe a que php ve 2015-02-30como una fecha válida porque cuando el día dado es mayor que la cantidad de días en el mes dado (o negativo) php se transfiere al mes siguiente. Dado que se garantiza que la fecha tendrá el formato, yyyy-mm-ddesto se puede corregir cambiando la devolución a return (bool)strtotime($myDateString) && date("Y-m-d", strtotime($myDateString)) == $myDateString;.
elitechief21
2
¿Por qué (bool)strtotime('s')sale como verdadero?
Peon
esto también devuelve 1 checkIsAValidDate ("F");
Vaibhav Bhanushali
podemos usar $myDateString = str_replace("/", '-', $myDateString);antes de regresar si la cadena de fecha contiene barras (/) como: - dd / mm / aaaa
Yashrajsinh Jadeja
37

Usar de manera simple con la función prepilada de php:

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

Prueba

   checkmydate('2015-12-01'); //true
   checkmydate('2015-14-04'); //false
viña
fuente
1
Buena solución directa, funcionó por primera vez, gracias :)
David Bell
Nuevamente, cuando se usa una prueba, dentro de un ifpara regresar simplemente trueo false, regresar la prueba en sí.
Victor Schröder
44
Esto supone que hay al menos 3 elementos en la matriz $ tempDate.
persona27
2
@ person27:return sizeof($tmpDate) == 3 && checkdate($tmpDate[1]...
neurino
@vineet: esto falla. Si el año es 2, 20, 202, 2020o incluso si el año es 20201- que devuelve verdadero cada vez.
Rolinger
16

Determine si la cadena es una fecha, incluso si la cadena es un formato no estándar

(Strtotime no acepta ningún formato personalizado)

<?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');
migli
fuente
Al usar una prueba, dentro de una ifpara regresar simplemente trueo false, devolver la prueba en sí.
Victor Schröder
Pero 2018-3-24 devuelve falso, el método recibe 2018-3-24, cuando se aplica el formato, devuelve 2018-03-24; ¿Cómo puedo volver verdadero de dos maneras?
Aquiles Perez
12

Esta opción no solo es simple sino que también acepta casi cualquier formato, aunque con formatos no estándar puede tener errores.

$timestamp = strtotime($date);
return $timestamp ? $date : null;
galki
fuente
¡Esta debería haber sido la respuesta aceptada! Mucho, mucho más simple.
Webmaster G
2
Es importante tener en cuenta que esto no funcionará con un formato británico (d / m / Y), ya que supondrá que está convirtiendo el estadounidense (m / d / Y). ¡Parece funcionar solo si el día es inferior a 12!
Sylvester Saracevas
@galki: probé esto y falla ciertos valores. Si $ date = '202-03-31' devuelve verdadero. Pero esa no es una fecha válida. Descubrí que si altera el año a un año no válido, siempre devuelve verdadero.
Rolinger
@rolinger extraño ... tal vez está viendo 202AD? ¿Qué marca de tiempo de año da 'strtotime'?
galki
@galki: no estoy seguro, pero 202devuelve un número negativo, que aún pasa la prueba.
Rolinger
10

También puede analizar la fecha del mes y año y luego puede usar la función PHP checkdate()que puede leer aquí: http://php.net/manual/en/function.checkdate.php

También puedes probar este:

$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';
    }
Suvash sarker
fuente
en caso de febrero (como comentó elitechief21) la función esValidDate ($ date) {return preg_match ("/ ^ [0-9] {4} - (0 [1-9] | 1 [0-2]) - - 0 [1-9] | [1-2] [0-9] | 3 [0-1]) $ / ", $ fecha) && date (" Ymd ", strtotime ($ date)) == $ date; }
abdulwadood
44
Esta solución es muy pobre, ya que no verifica la validez de la fecha en ningún sentido. Cualquier mes puede tener 31 días, incluido febrero. Cualquier año puede tener 29 de febrero. Validar las fechas usando RegExp exigiría algo mucho más complejo, con referencias y puntos negativos.
Victor Schröder
9

La forma más fácil de verificar si la fecha dada es válida, probablemente convirtiéndola a unixtime usando strtotime, formateándola al formato de la fecha dada, y luego comparándola:

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

Por supuesto, puede usar expresiones regulares para verificar la validez, pero se limitará al formato dado, cada vez que tenga que editarlo para satisfacer otros formatos, y también será más de lo requerido. Las funciones integradas son la mejor manera (en la mayoría de los casos) para lograr trabajos.


fuente
1
Siento que esta respuesta es de muy baja calidad, especialmente teniendo en cuenta que ya hay respuestas de tiempo de espera.
GrumpyCrouton
44
Esta es la respuesta más corta y funciona. Es un poco duro decir que es de baja calidad.
Tim Rogers
@ user4600953: este es el más fácil que funciona. Muchos otros dicen usar checkdate(), pero encuentro que la fecha de verificación falla si el año es CUALQUIER valor: 2, 20, 202, 2020, 20201todos devuelven verdadero. Voy con tu solución!
Rolinger
7

De acuerdo con la respuesta de cl-sah, pero esto suena mejor, más corto ...

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

Prueba

checkmydate('2015-12-01');//true
checkmydate('2015-14-04');//false
sdotbertoli
fuente
Sin count($tempDate) === 3embargo
deberá
@VDarricau no, la fecha de verificación bombardeará si faltan, podría escribir isset () para cada uno, pero simplemente suprimiría las advertencias
Sr. Heelis
7

Tengo esta cosa que, incluso con PHP, me gusta encontrar soluciones funcionales . Entonces, por ejemplo, la respuesta dada por @migli es realmente buena, altamente flexible y elegante.

Pero tiene un problema: ¿qué sucede si necesita validar muchas cadenas DateTime con el mismo formato? Tendría que repetir el formato en todo el lugar, lo que va en contra del principio DRY . Podríamos poner el formato en una constante, pero aún así, tendríamos que pasar la constante como argumento para cada llamada a la función.

¡Pero no temas más! ¡Podemos usar el curry para nuestro rescate! PHP no hace que esta tarea sea agradable, pero aún es posible implementar curry con PHP:

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

Entonces, ¿qué acabamos de hacer? Básicamente envolvimos el cuerpo de la función de forma anónima y devolvimos dicha función. Podemos llamar a la función de validación de esta manera:

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

Sí, no es una gran diferencia ... pero el poder real proviene de la función parcialmente aplicada , hecha posible al 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

Programación funcional FTW!

Victor Schröder
fuente
2
La mejor respuesta de un IMHO aplastante (resuelve el problema específico del OP con mayor flexibilidad y casi la misma cantidad de código que el resto de las respuestas)
StubbornShowaGuy
En mi humilde opinión, esta es una programación realmente fea, solo ponga sus valores en una matriz y repítalos para validarlos, ¡pero no haga esto!
Tim
Tengo curiosidad @Tim, ¿podría darnos un ejemplo de su validación de matriz / bucle?
Victor Schröder
5

Me temo que la solución más votada ( https://stackoverflow.com/a/19271434/3283279 ) no funciona correctamente. El cuarto caso de prueba (var_dump (validateDate ('2012-2-25')); // falso) está mal. La fecha es correcta, porque corresponde al formato: el m permite un mes con o sin cero a la izquierda (ver: http://php.net/manual/en/datetime.createfromformat.php ). Por lo tanto, una fecha 2012-2-25 está en formato Ymd y el caso de prueba debe ser verdadero, no falso.

Creo que la mejor solución es probar el posible error de la siguiente manera:

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

    return $errors['warning_count'] === 0 && $errors['error_count'] === 0;
}
Barvajz
fuente
3

¿Que tal este?

Simplemente usamos un bloque try-catch.

$dateTime = 'an invalid datetime';

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

Este enfoque no se limita a un solo formato de fecha / hora, y no necesita definir ninguna función.

Julian
fuente
esto no funcionará para el valor de fecha y hora 0000-00-00 00:00:00
Naseeruddin VN
@NaseeruddinVN '0000-00-00 00:00:00'es un valor de fecha y hora válido. Es solo el primero el valor. Sin embargo, la propiedad de fecha del objeto datetime será '-0001-11-30 00:00:00'.
Julian
1

Solución probada de 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;
    }

Esto devolverá nulo si la fecha no es válida o no tiene el formato aaaa-mm-dd; de lo contrario, devolverá la fecha.

Akumaburn
fuente
1

Validar con la función checkdate :

$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
}
El príncipe Ahmed
fuente
Documentación para la fecha de verificación: w3schools.com/php/func_date_checkdate.asp
Prince Ahmed
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) === '-');
}
Marco Demaio
fuente
-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);
        }

    }
Subham Ghorui
fuente
1
El código sin ninguna explicación no es muy útil.
Gert Arnold
-2

Prueba esto:

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