# How to subtract months from time?

Hi there,
Im reading a date out of a database and I need to subtract exactly 1
month from that date? It needs to be bullet proof so that if the date
says 31 and the previous month only has 28 days it wont just subtract 1
from the month and make an illegal date.

Thanks

Petr

On 10/22/06, Petr [email protected] wrote:

Hi there,
Im reading a date out of a database and I need to subtract exactly 1
month from that date? It needs to be bullet proof so that if the date
says 31 and the previous month only has 28 days it wont just subtract 1
from the month and make an illegal date.

http://rails.rubyonrails.org/classes/ActiveSupport/CoreExtensions/Time/Calculations.html#M000231

I noticed see ago(), months_ago(), and years_ago(). Does this mean to
calculate days ago you have to use something like this:(?)

/ set constant
@day_in_seconds = 606024

/ grab time past from user input
gets @days_gone_by

/ calculate and print
puts Time.ago(@day_in_seconds * @days_gone_by)

Or would the third line be Time.now.ago()? Too bad there isn’t just
aren’t days_ago() and weeks_ago() methods. Is there an easier way?

You are right. In fact you can do it all on one line:

irb(main):001:0> require ‘date’
=> true
irb(main):002:0> puts Date.today - 7
2006-10-16
=> nil

Much easier than all of my previous code!

This might help for calculating days ago:

C:\WINDOWS>irb
irb(main):001:0> require ‘date’
=> true
irb(main):002:0> t = Date.today
=> #<Date: 4908063/2,0,2299161>
irb(main):004:0> puts t
2006-10-23
=> nil
irb(main):005:0> puts t - 7
2006-10-16
=> nil
irb(main):006:0>

On Oct 23, 12:01 am, Taylor S. [email protected]

I think you can just use the << or >> as in:

irb(main):001:0> require “Date”
=> true
irb(main):002:0> d = Date.new(1997, 12, 31)
=> #<Date: 4901627/2,0,2299161>
irb(main):003:0> d.to_s
=> “1997-12-31”
irb(main):004:0> d2 = d >> 1
=> #<Date: 4901689/2,0,2299161>
irb(main):005:0> d2.to_s
=> “1998-01-31”
irb(main):006:0> d2 = d >> 2
=> #<Date: 4901745/2,0,2299161>
irb(main):007:0> d2.to_s
=> “1998-02-28”
irb(main):008:0> d2 = d << 1
=> #<Date: 4901565/2,0,2299161>
irb(main):009:0> d2.to_s
=> “1997-11-30”
irb(main):010:0>

And I think Date is already included in Rails controllers so you don’t
need to do the include.

Taylor S. wrote:

Have I missed a ‘require’ or am I stringing the methods in the wrong
order?

If you want to use it in irb, try to include active_support first:

irb(main):001:0> require ‘active_support’

Cheers.

Of course now when I go back to answer the OP’s question I cannot!

irb(main):001:0> require ‘date’
=> true
irb(main):018:0> Puts Date.today.months_ago(1)
NoMethodError: undefined method `months_ago' for #<Date: 4908063/2,0,2299161> irb(main):030:0> Time.now.months_ago(1) NoMethodError: undefined method`months_ago’ for Mon Oct 23 03:23:22
-0400 2006:

Have I missed a ‘require’ or am I stringing the methods in the wrong
order?

days_ago and weeks_ago aren’t there because they are easy: days_ago is
just n * 86400 seconds ago, so you can just write 3.days.ago
months_ago is more complicated because of the varying numbers of day in
a month, you need to now what the value of now is, which is why we have
months_ago, months_since

A word of warning about Date, Date can be quite slow compared to Time.
Most of the time you won’t care, but I was writing a calendaring style
app that did a lot of that sort of calculations and using profiling
showed that the various Date operations were a big slowdown

Fred

Frederick C. wrote:

days_ago and weeks_ago aren’t there because they are easy: days_ago is
just n * 86400 seconds ago, so you can just write 3.days.ago
months_ago is more complicated because of the varying numbers of day in
a month, you need to now what the value of now is, which is why we have
months_ago, months_since

A word of warning about Date, Date can be quite slow compared to Time.
Most of the time you won’t care, but I was writing a calendaring style
app that did a lot of that sort of calculations and using profiling
showed that the various Date operations were a big slowdown

Fred

Can someone elaborate on the Date Vs Time speed comment?

I am about to write a lot of calendar like functionality that doesn’t
really need hour/minute level details and was thinking using Date
throughout. But if it means taking a performance hit, I will reconsider.

Thanks.

http://rails.rubyonrails.org/classes/ActiveSupport/CoreExtensions/Time/Calculations.html#M000231

@time.advance :months => 7

@time.advance :days => -15

Chet wrote:

showed that the various Date operations were a big slowdown

Posted via http://www.ruby-forum.com/.

Simply put, Time values are stored as a long integer and all math on
them is done by adding or subtracting two values. This is very fast.
Date does a bunch of processing to make sure things work fine, which is
slower.

BTW…

irb>require ‘rubygems’
irb>require ‘ruby-units’ (gem for unit conversions and unit math)
irb>require ‘chronic’ (interprets natural language time specs)
irb>‘2 weeks’.from ‘today’
#=> Mon Nov 06 17:00:00 EST 2006
irb>‘2 weeks’.from ‘today’.to_date
=> 2006-11-06

also does… ‘ago’, ‘from’, ‘until’, etc…

but ruby-units doesn’t do months since they aren’t a fixed size
interval.
It does contain a number of helpers for converting back and forth
between time and date objects, and it will automatically convert to a
date object if any math you do takes you outside the normal range for a
Time object.

for more about ruby-units see
http://www.sciwerks.com/blog/2006/10/06/ruby-units-033/

_Kevin

Thanks everyone! This was very helpful. Some of my new favorite ways
to calculate time shifts:

irb(main):003:0> 1.month.ago
=> Sat Sep 23 14:22:27 -0400 2006

irb(main):004:0> 3.months.ago
=> Tue Jul 25 14:22:40 -0400 2006

irb(main):005:0> 2.days.ago
=> Sat Oct 21 14:22:45 -0400 2006

irb(main):006:0> 6.days.until
=> Tue Oct 17 14:22:58 -0400 2006

irb(main):015:0> Time.now.advance(:days => 7)
=> Mon Oct 30 14:25:36 -0500 2006

irb(main):016:0> Time.now.advance(:months => -2)
=> Wed Aug 23 14:26:00 -0400 2006

Seems like Date doesn’t support the advance() method though.