yellowreign
yellowreign

Reputation: 3638

Rails: Creating a Scope for Last Month

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

Answers (2)

Jared
Jared

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

Hassan Javeed
Hassan Javeed

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

Related Questions