Enumerating only months in a Date range?

Is there a straight-forward way to list all of the months in a Date
range? If I construct a date range, the each method iterates by day
only.

Thanks
-John
http://www.iunknown.com

There isn't a built-in way (that I know of), but it's pretty simple to
subclass date to make it work:

  class MonthlyDate < Date
    def succ
      self >> 1
    end
  end
  
  class Date
    def to_monthly
      m = MonthlyDate.new
      instance_variables.map do |var|
        m.instance_variable_set( var,instance_variable_get( var ) )
      end
      m
    end
  end

Then convert your Dates to MonthlyDates (using #to_monthly) before
creating your range. The range will now skip months rather than days.

HTH,
Mark

···

On 5/10/05, John Lam <drjflam@gmail.com> wrote:

Is there a straight-forward way to list all of the months in a Date
range? If I construct a date range, the each method iterates by day
only.

Thanks, Mark!

The self >> 1 line is um, rather mysterious to me. How does that skip by months?

Cheers,
-John
http://www.iunknown.com

Thanks, Mark!

The self >> 1 line is um, rather mysterious to me. How does that skip by months?

$ ri 'Date#>>'
---------------------------------------------------------------- Date#>>

···

On Wed, 2005-05-11 at 04:13 +0900, John Lam wrote:
     >>(n)
------------------------------------------------------------------------
     Return a new Date object that is +n+ months later than the current
     one.

     If the day-of-the-month of the current Date is greater than the
     last day of the target month, the day-of-the-month of the returned
     Date will be the last day of the target month.

Guillaume.

Cheers,
-John
http://www.iunknown.com

That's the bitshift operator, which is often used in classes for other
purposes. In the Date, it's used to add and subtract months:
Date.today << 2 will give you 2 months ago today, while Date.today >>
1 will give you next month today. I guess they decided to use it for
that because "+" and "-" were already taken, used for adding and
subtracting days.

Ranges use #succ (successor) to get the next object in a series. By
redefining #succ to return self >> 1 (self + 1 month), we get a range
of dates that skips by months rather than days.

cheers,
Mark

···

On 5/10/05, John Lam <drjflam@gmail.com> wrote:

Thanks, Mark!

The self >> 1 line is um, rather mysterious to me. How does that skip by months?

$ ri 'Date#>>'

Doh! Thanks Guillaume.

-John

The use of the bitshift operator surprised me. Crazy me, I was looking
for a next_month method :slight_smile:

Thanks again for the insight!
-John
http://www.iunknown.com