web-dev-qa-db-ja.com

日付文字列がその形式の有効な日付かどうかを正しく判断してください。

APIから日付文字列を受け取っています、そしてそれはyyyy-mm-ddとしてフォーマットされます。

私は現在、文字列フォーマットを検証するために正規表現を使用しています。これは問題なく動作しますが、文字列によっては正しいフォーマットであるが実際には無効な日付である場合があります。すなわち2013-13-01などです。

PHPに2013-13-01のような文字列を取り、それが有効な日付であるかどうかをyyyy-mm-ddの形式にするかどうかを知らせるより良い方法がありますか

156
Marty Wallace

この目的のために DateTime classを使用できます。

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

デモ!

384
Amal Murali

いずれかの文字列が日付かどうかを判別

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

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
29
vineet

stringが非標準形式であっても、stringが日付かどうかを判別します

(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');
14
migli

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

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

月の日付と年の日付を解析してから、PHP関数checkdate()を使用することもできます。これについては、 http://php.net/を参照してください。 manual/ja/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';
    }
9
Suvash sarker

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

私は、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!

6

与えられた日付が有効かどうかをチェックする最も簡単な方法はおそらくstrtotimeを使ってそれをunixtimeに変換し、与えられた日付のフォーマットにフォーマットしてからそれを比較することです:

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

もちろん、正規表現を使って妥当性をチェックすることもできますが、他のフォーマットを満たすためにそれを編集しなければならなくなるたびに、それは与えられたフォーマットに制限され、さらに必要以上になります。組み込み関数は(ほとんどの場合)仕事を達成するための最良の方法です。

5

これはどう?

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

$dateTime = 'an invalid datetime';

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

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

3
Julian

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

    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を返します。それ以外の場合は日付を返します。

1
Akumaburn

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
}
0
Prince Ahmed

投票されたほとんどの解決策( https://stackoverflow.com/a/19271434/3283279 )が正しく機能していないのではないでしょうか。 4番目のテストケース(var_dump(validateDate( '2012-2-25')); // false)は誤りです。それはフォーマットに対応するので日付は正しいです - mは月を許可します先行ゼロなしで:( http:// php参照) .net/manual/ja/datetime.createfromformat.php )したがって、日付2012-2-25は形式Y-m-dであり、テストケースはfalseではなくtrueでなければなりません。

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

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

    return $errors['warning_count'] === 0 && $errors['error_count'] === 0;
}
0
Barvajz
/*********************************************************************************
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) === '-');
}
0
Marco Demaio