自戒エントリー。
自分は Mongoid を使って開発してるんですけど、時間の境界値のテストが不十分で問題に遭遇したのでメモっておきます。
Mongoid には Date 型や DateTime 型があるけど、データベースにデータを保存するときには Time 型に変換されます(MongoDB に Date とか DateTime がないから?)。Mongo Shell で DB の中の値を見ると Time 型の値が入ってる。
だからクエリを生成するときに Date.today
はなるべく使わない方がいい。Date.today
では時間を 00:00:00 として扱い、月末のデータの取得に失敗する可能性が高いから。Rails console で確認すると、以下のようになります。
pry(1.9.3-p194)> 1.month.ago.end_of_month
# => Fri, 31 Aug 2012 23:59:59 JST +09:00
pry(1.9.3-p194)> Date.today.prev_month.end_of_month.to_time
# => 2012-08-31 00:00:00 +0900
上記は二つとも「先月末の月の終わり」を検索していますが、後者では時間が 00:00:00 になっています。例えば以下のような Mongoid でのクエリでは、8月31日の午前0時0分1秒以降に作成された Document を取得することが出来ません。ナンテコッタイ!!!
Model.where(:created_at.lte => Date.today.prev_month.end_of_month)
「Date.today
を時刻の生成の起点にしたとしても、to_time
してあげればいいのでは?」と思う方もいるでしょう。確認してみましょう。
pry(1.9.3-p194)> Date.today.prev_month.end_of_month.to_datetime
# => Fri, 31 Aug 2012 00:00:00 +0000
#prev_month
メソッドが呼び出された時点のオブジェクトの型は Date
型なので、Date
型に対して時間の操作を行って最後に DateTime
型に
結論
時刻まで考慮した時間の範囲でクエリを作るときは以下に留意すると良いでしょう。
-
Date.today
は使わない -
DateTime.now
か1.month.ago
などを使う