Reputation: 3638
I have a Rails 3.2 app with an Article model that has a field for date. I want to create a scope that will retrieve all records from last month. The problem I'm having is that my current scope is not including the first day of the month.
# article.rb
scope :last_month, lambda { { conditions: { date: last_month_range } } }
private
def self.last_month_range
1.month.ago.beginning_of_month..1.month.ago.end_of_month
end
When I run this it does this:
SELECT * FROM 'articles' WHERE ('articles`.'date' BETWEEN '2013-07-01 07:00' AND '2013-08-01 06:59:59')
When I look at the actual results it only starts with the articles with a date of 07-02-2013.
However, if I change the code to:
def self.last_month_range
(1.month.ago.beginning_of_month - 1.day)..1.month.ago.end_of_month
end
It does this:
SELECT * FROM 'articles' WHERE ('articles`.'date' BETWEEN '2013-06-30 07:00' AND '2013-08-01 06:59:59')
In that case it pulls in articles with dates of 6/31/2013.
Can someone please recommend a fix? Thank you!
Upvotes: 1
Views: 1707
Reputation: 3005
I got bit by a bug in the accepted answer:
Time.now.utc # => 2015-05-01 01:18:57 UTC
1.month.ago.utc.beginning_of_month #=> 2015-03-01 00:00:00 UTC
The problem is that the time is being converted to utc after the month is subtracted.
Here's a correct solution:
def self.last_month_range
Time.now.utc.prev_month.beginning_of_month..Time.now.utc.prev_month.end_of_month
end
Upvotes: 2
Reputation: 464
ActiveRecord does the conversion automatically to UTC, unless you have specified otherwise. You need to convert the range to UTC.
def self.last_month_range
1.month.ago.utc.beginning_of_month..1.month.ago.utc.end_of_month
end
Upvotes: 3