Today I Learned

hashrocket A Hashrocket project

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

More Info

See More #ruby TILs
Looking for help? Each developer at Hashrocket has years of experience working with Ruby applications of all types and sizes. We're an active presence at Ruby conferences, have written some of the most popular gems, and have worked on many of the web's Ruby on Rails success stories. Contact us today to talk about your Ruby project.