言語
Ruby on Rails
問題
7月1日~7月31日のデータを表示しようとしていたが、
31日のデータだけ一覧に出てこないバグが発生していた。
※追記2:ついでに7月1日0時~8時59分までの間も出ていなかった。
↓ハマっていたコード
date = Date.today
Test.where("? <= created_at && created_at <= ?",date.beginning_of_month,date.end_of_month)
原因
発行されたSQL文を確認したところ、
7月1日0時0分0秒~7月31日0時0分0秒に該当するレコードで検索していた。
date = Date.today
Test.where("? <= created_at && created_at <= ?",date.beginning_of_month,date.end_of_month.end_of_day)
=>SELECT `tests`.* FROM `tests` WHERE ('2019-07-01' <= exit_time && entrance_time <= '2019-07-31')
解決法
7月1日0時0分0秒~7月31日23時59分59秒に修正すると全部出た。
end_of_dayメソッド追加(その日の終わりの時刻)
date = Date.today
Test.where("? <= created_at && created_at <= ?",date.beginning_of_month,date.end_of_month.end_of_day)
=>SELECT `tests'.* FROM `tests` WHERE ('2019-07-01' <= exit_time && entrance_time <= '2019-07-31 14:59:59')
所感
日付だけで選択すると0時0分0秒で検索することになるんですね。
意外なところでつまづいてしまい解決に時間がかかりました。
追記(Timeオブジェクトを使用する)
Timeオブジェクトを使用することで、end_of_monthのみで動作するとコメントからのご指摘がありました。ありがとうございます。
Date.today.end_of_month #=> Sat, 31 Aug 2019
Time.current.end_of_month #=> Sat, 31 Aug 2019 23:59:59 JST +09:00
追記2(7月1日0時~8時59分が出ていない)
まだバグがありました。
DBには時差を引いた時間で登録しています。(-9時間で登録)
現実の7月1日0時~8時59分は、DB上では6月30日15時0分~6月30日23時59分になるわけです。
その状況でDBに7月1日からのデータをくれと言ったら出てこないですよね。
#解決法2
6月30日15時0分0秒から7月31日14時59分59秒でSQL文を発行する
beginning_of_dayメソッド追加(その日の始まりの時刻)
#発行されたSQL文
date = Date.today
Test.where("? <= created_at && created_at <= ?",date.beginning_of_month.beginning_of_day,date.end_of_month.end_of_day)
=>SELECT `tests'.* FROM `tests` WHERE ('2019-06-30 15:00:00' <= exit_time && entrance_time <= '2019-07-31 14:59:59')
所感2
長い……長すぎる……。全然スマートじゃないし。
DateオブジェクトではなくTimeオブジェクト使った方が良いですね。
いい勉強になりました。
#発行されたSQL文
date = Date.today
Test.where("? <= created_at && created_at <= ?",date.beginning_of_month.beginning_of_day,date.end_of_month.end_of_day)
=>SELECT `tests'.* FROM `tests` WHERE ('2019-06-30 15:00:00' <= exit_time && entrance_time <= '2019-07-31 14:59:59')
current = Time.current
Test.where("? <= dcreated_at && created_at <= ?",current.beginning_of_month,current.end_of_month)
=>SELECT `tests'.* FROM `tests` WHERE ('2019-06-30 15:00:00' <= exit_time && entrance_time <= '2019-07-31 14:59:59')