自戒エントリー。

自分は 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.now1.month.ago などを使う

コメント


(オプション)

(オプション)