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