marcamillion
marcamillion

Reputation: 33775

Why does a Time math calculation return one value in IRB but sends a diff value to SQL?

I have a method in my Post model that looks like this:

  def self.num_posted_x_days_ago(n)
    start_date = Time.now.midnight - n.day
    end_date = Time.now.midnight - (n+1).day
    where(created_at: start_date..end_date).count
  end

When I run it in IRB, I get this:

> Post.num_posted_x_days_ago(8)
   (0.3ms)  SELECT COUNT(*) FROM "posts"  WHERE ("posts"."created_at" BETWEEN '2015-02-27 05:00:00.000000' AND '2015-02-26 05:00:00.000000')
=> 0

Note that the Time on the date is 05:00:00.000000 for both the start_date and end_date.

But when I add a binding.pry into the method, and inspect both the start_date and end_date, I get this:

1] pry(Post)> start_date
=> 2015-02-26 00:00:00 -0500
[2] pry(Post)> end_date
=> 2015-02-25 00:00:00 -0500

Which shows the right time starting at midnight.

When I try to do it all manually at the console, I get this:

[31] pry(main)> Time.now.midnight
=> 2015-03-07 00:00:00 -0500
[32] pry(main)> Time.now.midnight - 9.days
=> 2015-02-26 00:00:00 -0500
[33] pry(main)> Time.now.midnight - 9.day
=> 2015-02-26 00:00:00 -0500

Notice that all the times show midnight.

What could be causing this mismatch?

Upvotes: 0

Views: 63

Answers (1)

makhan
makhan

Reputation: 4009

Database stores time in UTC. When you display it in console it shows you your local timezone.

Assuming you're interested in posts written on a particular day in your timezone the result should be what you expected. If you want to retrieve one day of posts in UTC timezone instead replace Time.now.midnight with Time.now.utc.midnight

---edit---

All dates stored in the database use UTC. Whenever Rails saves into database or retrieves from the database it converts from your local time zone to UTC or vice versa. That's why you see different times in SQL query. If you check the returned objects you will see that in fact these are correct results.

The only thing to keep in mind is that if you run the app on a different server it's likely that the system timezone will be different (it's a good practice to set server timezone to UTC), so Time.now.midnight will mean something different than on your local computer.

If you want to make sure Rails always retrieves posts from midnight of EST, you need to specify timezone explicitely:

Time.now.in_time_zone('EST').midnight

or (should switch to EDT when observing daylight saving time):

Time.now.in_time_zone('America/New_York').midnight

Upvotes: 3

Related Questions