

タイトルの通りです。  
行いたいバリデーションの内容は以下の３つです。

ユーザーが入力した日付が  
・5,10,15,20,25日である  
・月末である  
・過去30日以内である（１ヶ月に変更になる可能性有）

自分なりに書いてみたコードはこんな感じです。  
※$check['Date']には YYYY/mm/dd の形式でDBから取ってきたデータが入っています。

[code]

    //30日以内
    function DateChk30( $check ) {
        $today = date("Y/m/d");
        $checkunix = strtotime($check['Date']);
        $todatunix = strtotime($today);
        $diff = ($todatunix - $checkunix ) / ( 60 * 60 * 24);
    
        if ($diff < 30 ) 
        { 
            return true;
        } else {
            return false;
        }
    }
    
    //5,10,15,20,25,月末
    function DateChk( $check ) {
        $wk = date('Y/m/t');               //月末
        $tmp = substr($check['Date'], -2); //後ろ２文字
        $tmp = (int)$tmp;
    
        if ( ($tmp % 5) == 0 || $check['Date'] == $wk) 
        {
            return true;
        } else {
            return false;
        }
    }
    
[/code]

これだと31日が存在する月の30日でも通してしまうので困っています。  
switchを使って1日ずつ設定するしかないでしょうか。。  
何か良い方法がありましたらご教授ください。  
また、全体的に拙いソースだと思いますので、綺麗に書ける書き方があればご教授ください。

よろしくお願いします。


CC BY-SA 3.0
2017-08-09T08:29:11.763
37056
2017-08-24T07:31:20.920
24810
question
php
PHPで日付のバリデーションを行いたいです


多少冗長ですが、既存の関数をあまり変えないで見やすさ重視の場合は

[code]

    //5,10,15,20,25,月末
    function DateChk( $check ) {
        $wk = date('Y/m/t');               //月末
        $tmp = substr($check['Date'], -2); //後ろ２文字
        $tmp = (int)$tmp;
    
        if ( $tmp == 5 || $tmp == 10 || $tmp == 15 || $tmp == 20 || $tmp == 25 || $check['Date'] == $wk) 
        {
            return true;
        } else {
            return false;
        }
    }
    
[/code]

ワンライナーでソース量の少ないかつ意味もわかるような修正だと探したい日付をarrayで保持してのほうがいいかな。

[code]

    function DateChk( $check ) {
        if ($check['Date'] == date('Y/m/t') || in_array((int)substr($check['Date'], -2), array(5,10,15,20,25)))
        {
           return true;
        }
        return false;
    
    }
    
[/code]


CC BY-SA 3.0
2017-08-10T00:50:01.593
37079
2017-08-10T00:50:01.593
22665
37056
answer


mktime()を使うと、月、年、閏月を跨いでの処理が簡単になると思います。  
日付だけプラマイすればタイムスタンプを計算してくれます。

[code]

    //30日まえ
    $d30 = mktime(0, 0, 0, date("m")  , date("d")-30, date("Y"));
    echo date("Y/m/d H:i:s",$d30);
    
[/code]

同様に、月だけプラマイすれば、1ヶ月前、後も

[code]

    $d30 = mktime(0, 0, 0, date("m")-1  , date("d"), date("Y"));
    
[/code]

また、日付だけに変換とか使うとより楽しく作業出来るでしょう。

[code]

    echo date("d",time());
    
[/code]


CC BY-SA 3.0
2017-08-10T01:45:15.927
37083
2017-08-10T01:45:15.927
22793
37056
answer


  
挙動確認してませんが、例えば以下のようにしてみてはどうでしょうか。

・5,10,15,20,25日である

[code]

    function isMultipleOf5($date) {
        $day = date('d', strtotime($date));
        return (($day % 5) == 0 && $day < 30) ? true : false;
    }
    
[/code]

・月末である

[code]

    function getEndOfMonth($date) {
        $yearmonth = date('y/m', strtotime($date));
        return date('Y/m/d', strtotime("last day of {$yearmonth}"));
    }
    
    function isEndOfMonth($date) {
        $endOfMonth = getEndOfMonth($date);
        return ($date === $endOfMonth) ? true : false;
    }
    
[/code]

[PHP: 相対的な書式 - Manual](http://php.net/manual/ja/datetime.formats.relative.php)

・過去30日以内である（１ヶ月に変更になる可能性有）

[code]

    function within30Days($date) {
        $diff = strtotime("-30 days") - strtotime("{$date} -30 days");
    //    $diff = strtotime("-1 month") - strtotime("{$date} -1 month");
        return ($diff < 0) ? true : false;
    }
    
[/code]


CC BY-SA 3.0
2017-08-10T02:39:00.050
37084
2017-08-10T02:39:00.050
20043
37056
answer


こちらの条件を満たせる形で記述いたします。

> 5,10,15,20,25日である

モジュラ演算子を利用せずとも下記で対応可能です。  
また、特別な日付のみを追加する(1日など)などといったイレギュラーパターンにも対応可能です。  
こちらのほうが見栄えもよく、あとに利用する方がどういった処理をしているのか、わかりやすいかと思います。(PHPの性質を使い、あえてstrictパラメータは付与しません。)

[code]

    <?php
    if (in_array(date('d', strtotime($check['Date'])), [5, 10, 15, 20, 25])) {
         // do something
    }
    
[/code]

> 月末である

月末の判定は`date('t')`で判定できます。こちらもあえて、曖昧な比較にしています。

[code]

    <?php
    if (date('t') == date('d', strtotime($check['Date']))) {
         // do something
    }
    
[/code]

> 過去30日以内である（１ヶ月に変更になる可能性有）

過去30日以内であるということは現在の日付 - 30日なので、下記のようになります。  
変わる場合があるとのことなので、`-30 days`の箇所は月であれば`-1 month`に変えてください。

[code]

    <?php
    if (strtotime('-30 days', strtotime($check['Date'])) <= time()) {
        // do something
    }
    
[/code]

これらを組み合わせて下記となります。

[code]

    <?php
    if (
        in_array(date('d', strtotime($check['Date'])), [5, 10, 15, 20, 25]) &&
        date('t') == date('d', strtotime($check['Date'])) &&
        strtotime('-30 days', strtotime($check['Date'])) <= time()
    ) {
         // 条件に一致した場合の処理
    }
    
[/code]

上記で解説している方法は、PHPの曖昧な比較を利用した手法です。  
詳しく知りたい場合は下記をご覧ください。  
<http://php.net/manual/ja/function.in-array.php>  
<http://php.net/manual/ja/types.comparisons.php>

蛇足: 本来はイミュータブルなDateTimeを使うのが望ましいでしょうが、今回はstrtotimeで割愛します。

**2017/08/24 追記**

失礼しました。  
過去30日以内判定のロジックに誤りがありました。正確には下記のようになります。

[code]

    <?php
    if (strtotime($check['Date']) >= strtotime('-30 days')) {
        // do something
    }
    
[/code]


CC BY-SA 3.0
2017-08-22T15:46:23.660
37414
2017-08-24T07:31:20.920
2017-08-24T07:31:20.920
18542
18542
37056
answer