Determinare correttamente se la stringa di data è una data valida in quel formato


184

Ricevo una stringa di data da un'API ed è formattata come yyyy-mm-dd.

Attualmente sto usando un regex per convalidare il formato della stringa, che funziona bene, ma posso vedere alcuni casi in cui potrebbe essere un formato corretto in base alla stringa ma in realtà una data non valida. cioè 2013-13-01, per esempio.

Esiste un modo migliore in PHP di prendere una stringa come 2013-13-01e dire se è una data valida o no per il formato yyyy-mm-dd?


Possibile duplicato della convalida della data
Vivek Athalye,

2
La risposta qui è comunque molto migliore.
Sebastien,

Risposte:


454

Puoi usare la DateTimeclasse per questo scopo:

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

[ Funzione presa da questa risposta . Anche su php.net . Originariamente scritto da Glavić . ]


Casi 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

Demo!


14
Se stai usando PHP 5.2.x, dovresti usare strtotimeper ottenere il timestamp di unix e poi date('Y-m-d', $t)per ottenere la data della stringa. Quindi li confronti proprio come questa risposta.
pedromanoel,

2
@pedromanoel: per l'input datetime standard è possibile utilizzare strtotime, ma per formati non standard che strtotimenon riconoscono, sarà necessaria un'altra soluzione. E per php versione 5.2 il supporto è stato interrotto a gennaio 2011, per il supporto 5.3 è stato interrotto ad agosto 2014.
Glavić,

2
considera questa datavar_dump( validateDate('2012-2-9'));
regnosamente il

4
La funzione funziona correttamente. Restituiva falso perché il formato thr specificato non era corretto. Se si desidera utilizzare giorno e mese senza zeri 'Y-n-j'iniziali, il formato dovrebbe essere @reignsly.
Amal Murali,

1
@ AntonyD'Andrea: no, non funzionerà senza quella parte. Perché $dnon sarà falso nel dare la data, che ha parti in eccesso, come il 13 ° mese (2013-13-01). Ma dipende davvero da cosa vuoi. Se, ad esempio validateDate('2015-55-66'), devi essere valido, sì, devi solo verificare se $dè oggetto o no.
Glavić,

81

Determina se una stringa è una data

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

2
Ciò convalida un'intera gamma di formati di data validi non solo yyyy-mm-dd.
EWit

10
@MichelAyres questo perché php vede 2015-02-30come una data valida perché quando il giorno indicato è maggiore del numero di giorni in un determinato mese (o negativo), il php passa al mese successivo. Poiché la data è garantita nel formato, yyyy-mm-ddquesto può essere risolto modificando il ritorno in return (bool)strtotime($myDateString) && date("Y-m-d", strtotime($myDateString)) == $myDateString;.
elitechief21,

2
Perché (bool)strtotime('s')viene fuori vero?
Peon

questo restituisce anche 1 checkIsAValidDate ("F");
Vaibhav Bhanushali,

possiamo usare $myDateString = str_replace("/", '-', $myDateString);prima del ritorno se la stringa della data contiene barre (/) come: - gg / mm / aaaa
Yashrajsinh Jadeja

37

Utilizzare in modo semplice con la funzione prefabbricata php:

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

1
Bella soluzione semplice, ha funzionato la prima volta, grazie :)
David Bell,

Ancora una volta, quando si utilizza un test, all'interno di ifper restituire semplicemente trueo false, restituire il test stesso.
Victor Schröder,

4
Ciò presuppone che ci siano almeno 3 elementi nell'array $ tempDate.
persona27

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

@vineet - questo fallisce. Se l'anno è 2, 20, 202, 2020o anche se l'anno è 20201- restituisce vero ogni volta.
Rolinger

16

Determina se stringa è una data, anche se stringa è un formato non standard

(strtotime non accetta alcun formato personalizzato)

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

Quando si utilizza un test, all'interno di ifper restituire semplicemente trueo false, restituire il test stesso.
Victor Schröder,

Ma 2018-3-24 sta tornando falso, il metodo riceve 2018-3-24, quando si applica il formato ritorno 2018-03-24; come posso tornare vero in due modi?
Aquiles Perez,

12

Questa opzione non è solo semplice ma accetta anche quasi tutti i formati, anche se con formati non standard può essere errata.

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

Questa avrebbe dovuto essere la risposta accettata! Molto, molto più semplice.
Webmaster G,

2
È importante notare che questo non funzionerà con un formato britannico (d / m / Y) poiché supporrà che sta convertendo l'americano (m / d / Y). Sembrerà funzionare solo se il giorno è inferiore a 12!
Sylvester Saracevas,

@galki - ho provato questo e fallisce alcuni valori. Se $ date = '202-03-31' restituisce vero. Ma questa non è una data valida. Ho scoperto che se si modifica l'anno in un anno non valido, ritorna sempre vero.
Rolinger

@Rolinger strano ... forse sta vedendo 202AD? Quale data e ora dà 'strtotime'?
galki

@galki - non certo, ma 202restituisce un numero negativo - che supera comunque il test.
Rolinger

10

Puoi anche analizzare la data per la data e l'anno del mese e quindi puoi utilizzare la funzione PHP checkdate()che puoi leggere qui: http://php.net/manual/en/function.checkdate.php

Puoi anche provare questo:

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

in caso di febbraio (come commentato da elitechief21) la funzione 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
Questa soluzione è molto scarsa, in quanto non controlla la validità della data in alcun senso. Ogni mese può avere 31 giorni, incluso febbraio. Ogni anno può avere il 29 febbraio. Convalidare le date usando RegExp richiederebbe qualcosa di molto più complesso, con riferimenti a ritroso e prospettive negative.
Victor Schröder,

9

Il modo più semplice per verificare se una determinata data è valida probabilmente la converte in unixtime usando strtotime, formattandola nel formato della data data, quindi confrontandola:

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

Ovviamente puoi usare l'espressione regolare per verificare la validità, ma sarà limitato a un determinato formato, ogni volta che dovrai modificarlo per soddisfare altri formati, e inoltre sarà più del necessario. Le funzioni integrate sono il modo migliore (nella maggior parte dei casi) per ottenere lavori.


1
Sento che questa risposta è di qualità piuttosto bassa, specialmente considerando che ci sono già risposte da tempo.
GrumpyCrouton,

4
Questa è la risposta più breve e funziona. È un po 'duro dire che è di bassa qualità.
Tim Rogers,

@ user4600953 - questa è la più semplice che funzioni. Molti altri stanno dicendo di usare checkdate()- ma sto scoprendo che la data di arresto fallisce se l'anno è QUALSIASI valore: 2, 20, 202, 2020, 20201- tutti restituiscono vero. Vado con la tua soluzione!
Rolinger

7

In accordo con la risposta di cl-sah, ma questo suona meglio, più breve ...

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

Test

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

Avrai bisogno di verificare se count($tempDate) === 3però
VDarricau

@VDarricau no, il checkdate bombarderà se mancano, potresti scrivere isset () per ognuno ma sopprimerei semplicemente gli avvertimenti
Mr Heelis,

7

Ho questa cosa che, anche con PHP, mi piace trovare soluzioni funzionali . Quindi, ad esempio, la risposta data da @migli è davvero buona, altamente flessibile ed elegante.

Ma ha un problema: cosa succede se è necessario convalidare molte stringhe DateTime con lo stesso formato? Dovresti ripetere il formato dappertutto, ciò che va contro il principio DRY . Potremmo mettere il formato in una costante, ma dovremmo comunque passare la costante come argomento a ogni chiamata di funzione.

Ma non temere più! Possiamo usare il curry in nostro soccorso! PHP non rende piacevole questo compito, ma è ancora possibile implementare il curry con PHP:

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

Quindi, cosa abbiamo appena fatto? Fondamentalmente abbiamo racchiuso il corpo della funzione in un anonimo e restituito invece tale funzione. Possiamo chiamare la funzione di validazione in questo modo:

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

Sì, non una grande differenza ... ma il vero potere deriva dalla funzione parzialmente applicata , resa possibile dal 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

Programmazione funzionale FTW!


2
La migliore risposta di un IMHO frana (risolve il problema specifico dell'OP con maggiore flessibilità e praticamente la stessa quantità di codice del resto delle risposte)
StubbornShowaGuy

IMHO questa è una programmazione davvero brutta, basta mettere i tuoi valori in un array e scorrere attraverso di essi per convalidare, ma per favore non farlo!
Tim

Sono curioso @Tim, potresti darci un esempio della tua convalida array / loop?
Victor Schröder,

5

Temo che la soluzione più votata ( https://stackoverflow.com/a/19271434/3283279 ) non funzioni correttamente. Il quarto caso di test (var_dump (validateDate ('2012-2-25')); // false) è errato. La data è corretta, perché corrisponde al formato: la m consente un mese con o senza zero iniziale (vedi: http://php.net/manual/en/datetime.createfromformat.php ). Pertanto una data 2012-2-25 è in formato Ymd e il caso di test deve essere vero non falso.

Credo che la soluzione migliore sia testare il possibile errore come segue:

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

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

3

Che ne dici di questo?

Usiamo semplicemente un blocco try-catch.

$dateTime = 'an invalid datetime';

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

Questo approccio non è limitato a un solo formato data / ora e non è necessario definire alcuna funzione.


questo non funzionerà per la registrazione del valore datetime 00:00:00
Naseeruddin VN

@NaseeruddinVN '0000-00-00 00:00:00'è un valore datetime valido. È solo il primo il valore. Tuttavia, la proprietà date dell'oggetto datetime sarà '-0001-11-30 00:00:00'.
Giuliano

1

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

Questo restituirà null se la data non è valida o non è nel formato aaaa-mm-gg, altrimenti restituirà la data.



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
Il codice senza alcuna spiegazione non è molto utile.
Gert Arnold,

-2

Prova questo:

$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";
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.