Laravel input type="time"を使ってcreated_atカラムを検索する


絞り込み検索などを実装する際、年月日は置いておき、時間だけで検索したい!
という時に実装した事を忘備録としてまとめます。

抽象化するとわかりにくいので、具体例を用いてまとめます。
Laravelでブログを制作し、記事一覧ページなどから投稿記事を「作成時間」で検索する(あまり時間で検索することはないかもですが。。)機能を作るというシーンとします。
○時×分〜□時△分に投稿された記事を検索するイメージです。

形式の違い

timestamps (検索参照先)

Laravelでブログサイトなどを作る時、普通は記事のテーブルにtimestamps()created_atupdated_atのカラムを作成するかと思います。
今回はこのcreated_atを参照して記事を検索します。

created_atupdated_atなど、timestamps()で作成された値は、特別何も指定しなければ、Y-m-d H:i:sの形式(ex.2021年6月7日15時40分10秒に記事を作成したら2021-06-07 15:40:10)で保存されます。
時間だけで検索したいのに、、、Y-m-d が邪魔で実装しにくそう。。

input type="time" (検索入力元)

inputタグにはtype="time"という便利なオプションがあります。
時間の入力をinput type="time"を使うと、H:iの形式(ex.15:40)という値を簡単に入力する事ができます。
今回はこれを使います。

形式の違いまとめ

形式
timestamps() ※created_at Y-m-d H:i:s
input type="time" H:i

ここまでで上表の通り、表記の違いが生じる事がわかりました。
timestampsでは年月日に加えて秒まで記録してくれてます。今回に関しては余計な事を...!って感じです。
検索時にはこれを合わせなければなりませんが手間が掛かりそうですよね。

whereTime()を使う

そんな時に便利なのが、whereTime()です。
Laravelクエリビルダには時間に関係する色々なWHERE節が用意されています。
(whereDate / whereMonth / whereDay / whereYear / whereTime)

実装

検索フォームについて詳細は省略しますが、時間入力の部分はこんな感じにします。

list.blade.php
<input type="time" name="from_time">
<span>〜</span>
<input type="time" name="to_time">

○時×分〜□時△分の記事を検索。
nameの値は ○時×分:from_time □時△分:to_timeとします。

では、Controllerの実装です。

ArticleController.php
    public function list(Request $request)
    {
        // それぞれの入力値を取り出す
        $from_time = $request->from_time; //○時×分
        $to_time = $request->to_time; //□時△分

        // 両方の入力フォームに入力があった時のみ検索
        if(!empty($request->from_time) || !empty($request->to_time)){
            $query->whereTime('created_at','>=',$from_time.':00')->whereTime('created_at','<=',$until_time.':59');
            $articles = $query->get()->sortByDesc('created_at');
        }else{
            $articles = Article::all()->sortByDesc('created_at'); //検索がない時は全ての記事を取得
        }
        return view('article.list', ['articles' => $articles]);
    }

これで時間だけを指定して検索する事ができます。

解説

$query->whereTime('created_at','>=',$from_time.':00')->whereTime('created_at','<=',$until_time.':59');この一文についてですが、、、

ポイント①

まずwhereTime('created_at','>=',$from_time.':00')$from_time(○時×分)以降の記事を検索し、その記事群からwhereTime('created_at','<=',$until_time.':59')$to_time(□時△分)までの記事に絞り込むイメージです。
比較演算子が使えるのでwhereBetweenを使わなくても範囲指定できます。

ポイント②

形式の違いを確認した際、秒の有無がありましたが、これは$from_time.':00$until_time.':59で秒を無理やり付け足して解決です。