Tarih dizesinin bu biçimde geçerli bir tarih olup olmadığını doğru bir şekilde belirleyin


184

Bir API'dan bir tarih dizesi alıyorum ve olarak biçimlendirilmiş yyyy-mm-dd.

Şu anda Tamam çalışır dize biçimini doğrulamak için bir regex kullanıyorum, ancak dize ama aslında geçersiz bir tarihe göre doğru bir biçim olabilir bazı durumlarda görebilirsiniz. yani 2013-13-01, örneğin.

PHP'de 2013-13-01biçim için geçerli bir tarih olup olmadığını söylemek gibi bir dize almak için daha iyi bir yolu var mı yyyy-mm-dd?



2
Buradaki cevap zaten çok daha iyi.
Sebastien

Yanıtlar:


454

DateTimeSınıfı bu amaçla kullanabilirsiniz :

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

[ Bu cevaptan alınan işlev . Ayrıca php.net üzerinde . Aslen Glavić tarafından yazılmıştır . ]


Test senaryoları:

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
PHP 5.2.x kullanıyorsanız strtotime, unix zaman damgasını date('Y-m-d', $t)almak ve sonra dize tarihini almak için kullanmalısınız. Sonra da bu cevap gibi karşılaştırırsınız.
pedromanoel

2
@pedromanoel: standart datetime girişi için kullanabilirsiniz strtotime, ancak strtotimetanımayan standart olmayan formatlar için başka bir çözüme ihtiyacınız olacaktır. Ve php 5.2 sürümü için destek Ocak 2011'de durdu, 5.3 desteği için Ağustos 2014'te durdu.
Glavić

2
bu tarihi düşününvar_dump( validateDate('2012-2-9'));
15:59

4
İşlev düzgün çalışıyor. Belirttiğiniz thr biçimi yanlış olduğundan false döndürdü. Gün ve ayı 'Y-n-j'baştaki sıfır olmadan kullanmak istiyorsanız, biçim @reignsly olmalıdır .
Amal Murali

1
@ AntonyD'Andrea: hayır, bu kısım olmadan çalışmayacak. Çünkü $d13 ay (2013-13-01) gibi taşan parçalara sahip olan tarihi vermen yanlış olmaz. Ama bu gerçekten ne istediğine bağlı. Örneğin validateDate('2015-55-66')geçerli olması gerekiyorsa, evet, yalnızca $dnesne olup olmadığını kontrol etmeniz gerekir .
Glavić

81

Herhangi bir dizenin tarih olup olmadığını belirleme

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

2
Bu yalnızca geçerli tarih biçimlerinin tümünü doğrular yyyy-mm-dd.
EWit

10
@MichelAyres bunun nedeni php'nin 2015-02-30geçerli bir tarih olarak görülmesidir, çünkü verilen gün belirli bir aydaki (veya negatif) php'deki gün sayısından daha büyük olduğunda bir sonraki aya geçer. Tarihin formatta olması garanti edildiğinden yyyy-mm-ddbu, dönüşü değiştirerek düzeltilebilir return (bool)strtotime($myDateString) && date("Y-m-d", strtotime($myDateString)) == $myDateString;.
elitechief21

2
Neden (bool)strtotime('s')doğru çıkıyor?
Peon

bu ayrıca 1 checkIsAValidDate ("F") döndürür;
Vaibhav Bhanushali

$myDateString = str_replace("/", '-', $myDateString);Tarih dizesi eğik çizgiler (/) gibi içeriyorsa dönüşten önce kullanabiliriz : - gg / aa / yyyy
Yashrajsinh Jadeja

37

Php önceden oluşturulmuş fonksiyonu ile basit bir şekilde kullanın:

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

Ölçek

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

1
Güzel bir basit çözüm, ilk kez çalıştı, teşekkürler :)
David Bell

Yine, bir test kullanırken, ifbasitçe geri dönmek için trueya falseda testin kendisini döndürmek için.
Victor Schröder

4
Bu, $ tempDate dizisinde en az 3 öğe olduğunu varsayar.
person27

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

@vineet - bu başarısız olur. Yıl ise 2, 20, 202, 2020yıl ve hatta eğer 20201- her zaman true döndürür.
rolinger

16

Dize standart olmayan bir biçim olsa bile dizenin tarih olup olmadığını belirleme

(strtotime herhangi bir özel biçimi kabul etmez)

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

Bir test kullanırken, ifbasitçe geri dönmek için trueveya içinde falsetestin kendisini döndürün.
Victor Schröder

Ancak 2018-3-24 yanlış döndürüyor, yöntem, format uygulandığında 2018-3-24, 2018-03-24; iki şekilde nasıl doğru dönebilirim?
Aquiles Perez

12

Bu seçenek sadece basit değil, aynı zamanda hemen hemen her formatı kabul eder, ancak standart olmayan formatlarda buggy olabilir.

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

Bu kabul edilen cevap olmalı! Çok, çok daha basit.
Webmaster G

2
Bunun, Amerikan (m / d / Y) dönüştürdüğünü varsayacağından, İngiliz (d / m / Y) formatıyla çalışmadığını unutmayın. Sadece gün 12'den küçükse işe yarayacak gibi görünüyor!
Sylvester Saracevas

@galki - bunu test ettim ve bazı değerleri başarısız. $ Date = '202-03-31' ise true değerini döndürür. Ama bu geçerli bir tarih değil. Yılı geçerli olmayan bir yıla çevirirseniz her zaman doğru olduğunu fark ettim.
rolinger

@rolinger garip ... belki 202AD görüyor? 'Strtotime' hangi yılın zaman damgasını verir?
galki

@galki - belli değil, ancak 202yine de testi geçen negatif bir sayı döndürüyor.
rolinger

10

Ay tarih ve yıl için tarihi ayrıştırabilir ve daha sonra checkdate()burada okuyabileceğiniz PHP işlevini kullanabilirsiniz : http://php.net/manual/en/function.checkdate.php

Bunu da deneyebilirsiniz:

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

şubat durumunda (elitechief21 tarafından yorumlandığı gibi) işlevi isValidDate ($ date) {return preg_match ("/ ^ [0-9] {4} - (0 [1-9] | 1 [0-2]) - (0 [1-9] | [1-2] [0-9] | 3 [0-1]) $ / ", $ tarih) && tarih (" Ymd ", strtotime ($ tarih)) == $ tarih; }
abdulwadood

4
Bu çözüm, hiçbir şekilde tarih geçerliliğini kontrol etmediğinden çok zayıftır. Şubat dahil herhangi bir ay 31 gün sürebilir. Herhangi bir yıl 29 Şubat olabilir. RegExp kullanarak tarihleri ​​doğrulamak, geri referanslar ve olumsuz görünümlerle çok daha karmaşık bir şey gerektirir.
Victor Schröder

9

Belirli bir tarihin geçerli olup olmadığını kontrol etmenin en kolay yolu, büyük olasılıkla bunu kullanarak unixtime'a dönüştürmek strtotime, belirli bir tarihin biçimine biçimlendirmek ve karşılaştırmaktır:

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

Elbette geçerliliği kontrol etmek için normal ifadeyi kullanabilirsiniz, ancak verilen formatla sınırlı olacaktır, her seferinde başka bir formatı tatmin etmek için onu düzenlemek zorunda kalacaksınız ve ayrıca gerekenden daha fazla olacaktır. Yerleşik işlevler, işleri başarmanın en iyi yoludur (çoğu durumda).


1
Özellikle orada göz önünde bulundurarak bu yanıt oldukça düşük kaliteli olduğunu hissediyorum zaten strtotime cevapları.
GrumpyCrouton

4
Bu en kısa cevap ve işe yarıyor. Düşük kaliteli olduğunu söylemek biraz zor.
Tim Rogers

@ user4600953 - Bu en kolay çalışanıdır. Diğerleri bir sürü kullanmak söylüyor checkdate()- ama yıl herhangi bir değer ise checkdate başarısız buluyorum: 2, 20, 202, 2020, 20201- hepsi doğru döner. Çözümünüzle gidiyorum!
rolinger

7

Cl-sah'in cevabına göre, ama bu daha iyi, daha kısa ...

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

Ölçek

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

count($tempDate) === 3Yine de test etmeniz gerekecek
VDarricau

@VDarricau hayır yapmazsanız, checkdate eksikse bombalar, her biri için isset () yazabilirsiniz, ancak uyarıları bastırırım
Bay Heelis

7

PHP ile bile fonksiyonel çözümler bulmayı sevdiğim bir şey var . Yani, örneğin, migli'nin verdiği cevap gerçekten iyi, çok esnek ve zarif.

Ancak bir sorunu var: Aynı formatta çok sayıda DateTime dizesini doğrulamanız gerekiyorsa ne olur? DRY prensibine aykırı olan formatı her yerde tekrarlamanız gerekir . Biçimi bir sabit içine koyabiliriz, ancak yine de, sabiti her işlev çağrısına bağımsız değişken olarak geçirmemiz gerekir.

Ama artık korkma! Köriyi kurtarmamıza kullanabiliriz ! PHP bu görevi keyifli hale getirmez, ancak PHP ile köri uygulamak hala mümkündür:

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

Peki, az önce ne yaptık? Temelde işlev gövdesini anonim olarak sardık ve bunun yerine bu işlevi döndürdük. Doğrulama işlevini şu şekilde çağırabiliriz:

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

Evet, büyük bir fark değil ... ama gerçek güç , körüklenerek mümkün kılınan kısmen uygulanan fonksiyondan geliyor :

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

Fonksiyonel programlama FTW!


2
Heyelan IMHO'nun en iyi cevabı (OP'nin özel problemini daha fazla esneklikle ve cevapların geri kalanıyla hemen hemen aynı miktarda kodla çözüyor)
StubbornShowaGuy

IMHO bu gerçekten çirkin bir programlama, sadece değerlerinizi bir diziye koyun ve doğrulamak için bunlara döngü yapın, ancak lütfen bunu yapmayın!
Tim

Merak ediyorum @Tim, bize dizi / döngü doğrulamanıza bir örnek verebilir misiniz?
Victor Schröder

5

En çok oy alan çözümün ( https://stackoverflow.com/a/19271434/3283279 ) düzgün çalışmadığından korkuyorum . Dördüncü test durumu (var_dump (validateDate ('2012-2-25')); // false) yanlış. Tarih doğrudur, çünkü biçime karşılık gelir - m , sıfır önde veya sıfır olmadan bir aya izin verir (bkz: http://php.net/manual/en/datetime.createfromformat.php ). Bu nedenle 2012-2-25 tarihi Ymd biçimindedir ve test durumu doğru değil yanlış olmalıdır.

Daha iyi bir çözümün olası hatayı aşağıdaki gibi test etmek olduğuna inanıyorum:

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

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

3

Buna ne dersin?

Sadece bir try-catch bloğu kullanıyoruz.

$dateTime = 'an invalid datetime';

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

Bu yaklaşım yalnızca bir tarih / saat formatıyla sınırlı değildir ve herhangi bir işlev tanımlamanız gerekmez.


bu tarih / saat değeri için çalışmaz 0000-00-00 00:00:00
Naseeruddin VN

@NaseeruddinVN '0000-00-00 00:00:00'geçerli bir tarih / saat değeridir. Bu sadece ilk değer. Ancak, datetime nesnesinin date özelliği olacaktır '-0001-11-30 00:00:00'.
Julian

1

Test edilmiş Regex çözümü:

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

Tarih geçersizse veya yyyy-aa-gg biçimi değilse bu değer null değerini döndürür, aksi takdirde tarihi döndürür.



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
Herhangi bir açıklama yapmadan kod çok kullanışlı değildir.
Gert Arnold

-2

Bunu deneyin:

$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";
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.