This project is archived and is in readonly mode.
ActiveSupport::Duration#* should return a Duration, not an Integer
Reported by Levin Alexander | February 8th, 2009 @ 08:35 PM | in 2.x
ActiveSupport::Duration does not implement multiplication. This can lead to unexpected behaviour when the result is used later with an object that special cases Duration instances (like Date)
>> require 'activesupport'
>> d = Date.new(2000,1,1)
=> Sat, 01 Jan 2000
>> expected = d + 2.days
=> Mon, 03 Jan 2000
>> actual = d + 1.day * 2
=> Thu, 09 Feb 2473   # offset is treated as number of days, not number of seconds
>> expected == actual
=> false
as testcase:
  def test_adding_multiples_of_duration_to_date
    Date.stubs(:today).returns Date.new(2000,1,1)
    assert_equal Date.today + 2.days, Date.today + (1.day * 2)
  end
the patch by Dan Barry on #879 fixes this
Comments and changes to this ticket
- 
            
        

Levin Alexander February 8th, 2009 @ 08:48 PM
however, this does not make "2 * 1.day" return a duration. The only way to do that would be to overwrite Numeric#* and test for the type of the argument.
I don't think the benefits would justify the performance hit of doing that.
 - 
            
        

Dan Barry February 9th, 2009 @ 01:04 AM
Actually, this does make 2 * 1.day return a duration. I don't know exactly why it works, but there's a test for it (test_multiplication_associativity).
 - 
            
        

Levin Alexander February 9th, 2009 @ 01:32 AM
no, it does not. This test fails:
def test_multiplication_associativity assert_equal "2.months", (1.month * 2).inspect assert_equal "2.months", (2 * 1.month).inspect endit just looks like it works, because durations are converted to seconds, before they are compared.
 - 
            
        

Levin Alexander February 9th, 2009 @ 01:40 AM
there is a small error in the test. It has to say "2 months" (without dot) instead of "2.months"
 - 
            
        

Dan Barry February 13th, 2009 @ 08:18 PM
Ah, good catch. I'll have to update the tests and figure that out.
 - 
            
        

Levin Alexander February 14th, 2009 @ 07:29 PM
Attached is just the Duration#* part of your (Dan's) patch, because that part seems uncontroversial.
This patch does not change behavior of Numeric*Duration and it does not implement Duration#/
It also does not check if the multiplier is a Fixnum because it is not clear what the fallback should be if it isn't (could call "to_i", "round", raise an argument error)
 - 
        

Pratik March 8th, 2009 @ 02:57 PM
- Assigned user set to Geoff Buesing
 - Tag changed from active_support, duration to active_support, duration, patch
 
 - 
        

Geoff Buesing January 28th, 2010 @ 03:15 AM
- State changed from new to wontfix
 
Unsure about this one. Reasons:
- 
With this change, 1.day * 2 returns a Duration, but 2 * 1.day returns a Fixnum. Seems odd and unexpected.
 - 
We disallow creating a Duration via Float#months and #years (e.g., you can no longer do "5.3.years"), but this patch would allow you to mutliply by a Float (e.g. "1.year * 5.3")
 
 
Create your profile
Help contribute to this project by taking a few moments to create your personal profile. Create your profile »
<h2 style="font-size: 14px">Tickets have moved to Github</h2>
The new ticket tracker is available at <a href="https://github.com/rails/rails/issues">https://github.com/rails/rails/issues</a>
People watching this ticket
Attachments
Tags
Referenced by
- 
        
          879 
          Finding the days/weeks/months/years between two dates
        @geoff, I just made a ticket for that: #1916