日付文字列がその形式で有効な日付かどうかを正しく判断します


184

APIから日付文字列を受信して​​いますが、形式はyyyy-mm-ddです。

現在、正規表現を使用して文字列形式を検証していますが、問題なく機能しますが、文字列によると正しい形式でも実際には無効な日付である場合があります。つまり2013-13-01、例えば。

などの文字列を取得し、2013-13-01それがフォーマットに対して有効な日付であるかどうかを確認するためのより良い方法はありますyyyy-mm-ddか?


PHPの

2
ここでの答えはとにかくはるかに優れています。
セバスチャン

回答:


454

DateTimeこの目的のためにクラスを使用できます:

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

[ この答えから取った機能。また、上のphp.net。もともとはGlavićによって書かれました]


テストケース:

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

デモ!


14
PHP 5.2.xを使用strtotimeしている場合は、を使用してUNIXタイムスタンプdate('Y-m-d', $t)を取得し、次に文字列日付を取得する必要があります。次に、この答えのようにそれらを比較します。
pedromanoel 2014年

2
@pedromanoel:標準の日時入力にはを使用できますがstrtotimestrtotime認識しない標準以外の形式の場合は、他の解決策が必要になります。また、phpバージョン5.2のサポートは2011年1月に停止し、5.3のサポートは2014
Glavić

2
この日付を検討してくださいvar_dump( validateDate('2012-2-9'));
確かに2015年

4
関数は正しく機能します。指定した形式が正しくないため、falseが返されました。先行ゼロなしで日と月を使用する場合、形式は'Y-n-j'、@reignslyにする必要があります。
Amal Murali 2015年

1
@ AntonyD'Andrea:いいえ、その部分がないと機能しません。ので$d偽ではありません、あなたはそれを13月(2013-13-01)のように、オーバーフローし部品を持っている日付を与えるに。しかし、それは本当にあなたが望むものに依存します。たとえばvalidateDate('2015-55-66')有効にする必要がある場合は、はい、$dオブジェクトかどうかを確認するだけで済みます。
Glavić

81

文字列が日付かどうかを判別

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

2
これにより、だけでなく、すべての有効な日付形式が検証されますyyyy-mm-dd
EWit 2014年

10
@MichelAyresこれは2015-02-30、指定された日が指定された月の日数より大きい場合(または負の場合)、phpが翌月にロールオーバーするため、phpが有効な日付と見なされるためです。日付の形式が保証yyyy-mm-ddされているため、戻り値をに変更することで修正できますreturn (bool)strtotime($myDateString) && date("Y-m-d", strtotime($myDateString)) == $myDateString;
elitechief21 2015

2
なぜ(bool)strtotime('s')本当のように見えるのですか?
Peon 2015年

これも1つのcheckIsAValidDate( "F");を返します。
Vaibhav Bhanushali

次の$myDateString = str_replace("/", '-', $myDateString);ように日付文字列にスラッシュ(/)が含まれている場合は、戻る前に使用できます:
-dd

37

PHPのビルド済み関数で簡単な方法で使用します。

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

テスト

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

1
素敵な簡単な解決策、最初に機能しました、ありがとう:)
David Bell

繰り返しになりますが、テストを使用する場合は、内でif単にを返すtruefalse、またはテスト自体を返します。
ビクターシュレーダー

4
これは、$ tempDate配列に少なくとも3つの要素があることを前提としています。
person27 2017年

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

@vineet-これは失敗します。年がある場合は2202022020年があるか、あっても20201-それは毎回trueを返します。
リンガー

16

文字列が非標準形式であっても、文字列が日付かどうかを判別

(strtotimeはカスタム形式を受け入れません)

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

テストを使用する場合は、内でif単純にを返すtruefalse、またはテスト自体を返します。
ビクターシュレーダー

しかし、2018-3-24がfalseを返している場合、メソッドは2018-3-24を受け取ります。2つの方法でtrueを返す方法
Aquiles Perez 2018

12

このオプションは単純なだけでなく、ほとんどすべての形式を受け入れますが、非標準形式ではバグが発生する可能性があります。

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

これは受け入れられるべき答えでした!はるかに簡単です。
ウェブマスターG

2
これはアメリカ式(m / d / Y)を変換することを前提としているため、イギリス式(d / m / Y)では機能しないことに注意してください。日が12未満の場合にのみ機能するようです。
シルベスターサラセバス

@galki-私はこれをテストしましたが、特定の値が失敗します。$ date = '202-03-31'の場合、trueを返します。しかし、それは有効な日付ではありません。年を無効な年に変更すると、常にtrueが返されることがわかりました。
リンガー

@rolinger奇妙なことです...多分それは202ADを見ていますか?「strtotime」は何年のタイムスタンプを提供しますか?
ガルキ

@galki-確かではありません202が、負の数を返します-それでもテストに合格します。
リンガー

10

月の日付と年の日付を解析して、checkdate()ここで読むことができるPHP関数を使用することもできます:http : //php.net/manual/en/function.checkdate.php

これを試すこともできます:

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

2月の場合(elitechief21によるコメント付き)関数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
このソリューションは、日付の有効性を何らかの意味でチェックしないため、非常に貧弱です。2月を含め、どの月にも31日あります。どの年でも2月の29を持つことができます。RegExpを使用して日付を検証するには、後方参照とネガティブルックアヘッドを使用して、はるかに複雑なものが必要になります。
ビクターシュレーダー

9

指定された日付が有効かどうかを確認する最も簡単な方法は、おそらくを使用して日付をunixtimeに変換strtotimeし、指定された日付の形式にフォーマットしてから、比較することです。

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

もちろん、正規表現を使用して有効性をチェックできますが、それは特定の形式に制限され、別の形式を満たすために編集する必要があるたびに、必要以上に多くなります。組み込み関数は、(ほとんどの場合)ジョブを達成するための最良の方法です。


1
私は特に存在を考えると、この答えはかなり低品質であることを感じて、すでにのstrtotime答えが。
GrumpyCrouton 2017

4
これは最も短い答えであり、機能します。クオリティが低いと言うのは少し厳しいです。
Tim Rogers、

@ user4600953-これが機能する最も簡単な方法です。他の多くの人が使用するように言っていますcheckdate()-しかし、年がすべての値である場合、チェックデートが失敗することがわかりました:2, 20, 202, 2020, 20201-すべてがtrueを返します。私はあなたの解決策で行きます!
リンガー

7

cl-sahの答えと一致していますが、この音はより良く、より短く...

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

テスト

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

かどうかをテストする必要がありcount($tempDate) === 3ます
VDarricau

@VDarricauいいえ、ありません。欠落している場合はcheckdateが爆破されます。1つ1つにisset()を書くことができますが、警告を抑制します
Mr Heelis

7

PHPを使用していても、機能的な解決策を見つけたいと思っています。したがって、たとえば、@ migliの回答は、非常に柔軟でエレガントです。

しかし、問題があります。同じ形式の多数のDateTime文字列を検証する必要がある場合はどうでしょうか。あちこちでフォーマットを繰り返す必要があり、DRYの原則に反します。フォーマットを定数に入れることもできますが、それでも、すべての関数呼び出しに引数として定数を渡す必要があります。

しかし、もう恐れるな!カレーを使って救助できる!PHPはこのタスクを快適にしませんが、PHPでカリー化を実装することはまだ可能です。

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

それで、私たちは今何をしたのですか?基本的に、関数本体を匿名でラップし、代わりにそのような関数を返しました。次のように検証関数を呼び出すことができます。

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

ええ、大きな違いではありません...しかし、本当の力はカレーによって可能になった部分的に適用された関数から来ます:

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

関数型プログラミングFTW!


2
地滑りIMHOによる最良の回答(OPの特定の問題をより柔軟に解決し、残りの回答とほぼ同じ量のコードを使用)
StubbornShowaGuy

これは本当に醜いプログラミングですが、値を配列に入れて検証するためにそれらをループするだけですが、これを行わないでください!
Tim

@Timに興味があります。配列/ループ検証の例を教えてください。
VictorSchröder18年

5

ほとんどの投票済みソリューション(https://stackoverflow.com/a/19271434/3283279)が正しく機能していないと思います。4番目のテストケース(var_dump(validateDate( '2012-2-25')); // false)は誤りです。日付は正しいです。これは形式に対応しているためです。mは先行ゼロ付きまたはなしの許可します(http://php.net/manual/en/datetime.createfromformat.phpを参照)。したがって、日付2012-2-25の形式はYmdであり、テストケースは偽ではなく真でなければなりません。

私はより良い解決策は次のように考えられるエラーをテストすることだと信じています:

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

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

3

これはどう?

単純にtry-catchブロックを使用します。

$dateTime = 'an invalid datetime';

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

このアプローチは、1つの日付/時刻形式に限定されず、関数を定義する必要はありません。


これは日時値0000-00-00 00:00:00では機能しません
Naseeruddin VN

@NaseeruddinVN '0000-00-00 00:00:00'は有効な日時値です。それは最初の値です。ただし、datetimeオブジェクトのdateプロパティはになります'-0001-11-30 00:00:00'
ジュリアン

1

テスト済みの正規表現ソリューション:

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

日付が無効またはyyyy-mm-dd形式でない場合はnullを返し、それ以外の場合は日付を返します。



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
説明のないコードはあまり役に立ちません。
ガートアーノルド

-2

これを試してみてください:

$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";
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.