2008/01/31

Beware of Rails date arithmetic

Having time and date methods on integers in Rails is nifty. Being able to say things like;

>> Date.today.to_time + 7.days
=> Thu Feb 07 00:00:00 +0000 2008
...is nice.

But, be careful about relying on this when doing arithmetic with months.

>> Date.new( 2008, 1, 1 ).to_time + 1.month
=> Thu Jan 31 00:00:00 +0000 2008
Wrong.

The problem is this;
>> 1.month / 86400.0
=> 30.0
i.e. a "month" is just 30 days' worth of seconds.

Similarly;
>> ( Date.new( 2008, 2, 1 ).to_time + 1.month )
=> Sun Mar 02 00:00:00 +0000 2008
There is a way to do month calculation correctly - use the built-in ActiveSupport::CoreExtensions::DateTime::Calculations like this;

>> Date.new( 2008, 1, 1 ).to_time.advance( :months => 1 )
=> Fri Feb 01 00:00:00 +0000 2008


>> Date.new( 2008, 2, 1 ).to_time.advance( :months => 1 )

=> Sat Mar 01 00:00:00 +0000 2008

Much better.