Casting Created At
Four posts have been created for ’Today I Learned’ since yesterday. This code looks like it would return that count, but it doesn’t.
Post.where('created_at between ? and ?', Date.yesterday, Date.today).count
(0.8ms) SELECT COUNT(*) FROM "posts" WHERE (created_at between '2015-06-09' and '2015-06-10’)
=> 2
It returns 2
; the two posts from yesterday but not the posts from today.
This is because Date.today
is a Ruby Date
object, which represents midnight on the given date, while created_at
is a Rails ActiveSupport::TimeWithZone
object, which includes time and zone details. Using Date.today
as a comparator actually excludes any posts created after midnight today.
One solution is to cast created_at
to a date:
Post.where('cast(created_at as date) between ? and ?', Date.yesterday, Date.today).count
(1.1ms) SELECT COUNT(*) FROM "posts" WHERE (cast(created_at as date) between '2015-06-09' and '2015-06-10')
=> 4
In the scope of this query, created_at
loses its time information, so a post created today will return true when compared to Date.today
. This is the Rails equivalent:
Post.last.created_at.to_date == Date.today
=> true
Tweet