trouble comparing datetimes in rspec

I'm getting a weird failure when trying to compare two datetimes. The
failure message is:

'Prompt as a featured prompt should set featured_on for public prompts'
FAILED
expected: Thu May 22 16:31:38 -0400 2008,
     got: Thu May 22 16:31:38 -0400 2008 (using ==)

My test:

  it "should set featured_on for public prompts" do
    date = 2.days.ago #cache timestamp
    @prompt = create_prompt(:scope => "public", :featured_on => nil)
    @prompt.make_featured :date => date
    @prompt.featured_on.should == (date)
  end

My model method:

def make_featured(options = {})
    unless scope == "private"
      options = {:date => Time.now}.merge(options)
      date = options[:date].to_s(:db)
      self.featured_on = date
      self.save
    else
      false
    end
  end

I recently upgraded to Rails 2.1_RC1, so I'm hoping that didn't foul
anything up. Also, what's weird is that in my method I'm setting
:featured_on to date.to_s(:db). So if I run a prompt.inspect in the
console, it returns "featured_on: '2008-05-24 16:20:45'", but if I just
type "prompt.featured_on" in the console, it returns Sat May 24 16:20:45
-0400 2008, so I don't know if rails is doing any auto-conversion there.
But that seems almost totally unrelated to my test failing when
comparing two identical date values.

Any help?

Hi Bryan.

Could it be you're comparing the value date in your spec, which is of
class Time, to a string (the value of featured_on)?

mike

Could it be you're comparing date in your spec, which is of class
Time, to a string (the value of featured_on)?

That doesn't seem to be the problem. If I convert both values in the
comparison to String, it will pass the test, but not if I just convert
the value I'm comparing against.

It also seems that regardless of whether I pass in a Time object or a
String to the record, Rails returns a Time object (which I assume is
because the column is set as datetime). Both of the objects I'm
comparing in my test belong to the Time class.

Is rspec comparing on the objects themselves, which will never be
equal, instead of the value?

I did a quick test in the console (although this may not help at all)

d1 = 2.days.ago

=> Thu May 22 17:03:10 -0400 2008

d2 = Time.parse(d1.to_s)

=> Thu May 22 17:03:10 -0400 2008

d1 == d2

=> false

but here they are of course equal because they reference the same
object

d1 = d2 = 2.days.ago

=> Thu May 22 17:03:10 -0400 2008

d1 == d2

=> true

cheers.
mike

Is rspec comparing on the objects themselves, which will never be
equal, instead of the value?

I did a quick test in the console (although this may not help at all)

d1 = 2.days.ago

=> Thu May 22 17:03:10 -0400 2008

d2 = Time.parse(d1.to_s)

=> Thu May 22 17:03:10 -0400 2008

d1 == d2

=> false

>> d1 = 2.days.ago
=> Fri May 23 11:51:52 UTC 2008
>> d2 = Time.parse(d1.to_s)
=> Fri May 23 11:51:52 UTC 2008
>> d1.usec
=> 7070
>> d2.usec
=> 0

The roundtrip via to_s (or the database) discards the fractional part of the time.

Fred

oh yes, I see that now. Thank you.

Ah ha! Thank you both for helping me out. I'm just going to stick to
comparing them both as strings.

Try something like this:

it “should blablabla” do
time = Time.now
Time.stub!(:now).and_return(now)
@foo.something_that_calls_time_now
@foo.time_variable.should == time
end

Stubbing Time.now [or whatever Time/Date method you use] is gonna be the trick. HTH

RSL