ruby_time

Time comparison in Ruby

| 7 Comments

I believe every ruby developer has faced time comparison issue at least once and tests are one of the possible areas where it may happen. RSpec message like this may confuse:

What’s wrong?

Investigation

Let’s create two Time objects:

At the first glance, they are equal. But it’s not true:

The issue occurs because ruby Time makes comparison with fractions of seconds. We may use to_f method to see the difference between t1 and t2:

or to_r method to get rational numbers:

Summary

If you don’t care about milliseconds, you may compare timestamps using to_i method:

or make a new Time object from timestamps to have better RSpec failure messages:

But even better to use fixed times in our tests.

Share
* Railsware is a premium software development consulting company, focused on delivering great web and mobile applications. Learn more about us.
  • Maxime Garcia

    Or instead of rounding to the second, you embrace a difference of less a second :
    expect(t1).to be_within(1.second).of(t2)

    • http://shime.github.com/ Hrvoje Šimić

      1.second is from ActiveSupport, so this will not work in plain old Ruby.

      I prefer to use the technique Lionel mentioned above, just nicely format the time and then compare strings.

      RSpec::Matchers.define :be_the_same_time_as do |expected|
      match do |actual|
      expect(expected.strftime("%d-%m-%Y %H:%M:%S")).to eq(actual.strftime("%d-%m-%Y %H:%M:%S"))
      end
      end

      describe "time comparison" do
      it "passes for equal time" do

      expect(Time.now).to be_the_same_time_as Time.now
      end
      end

      • http://emaxime.com/ Maxime Garcia

        irb(main):001:0> t1 = Time.now
        => 2014-04-14 23:08:45 +0200
        irb(main):002:0> t1.to_f
        => 1397509725.5656137
        irb(main):003:0> Time.now – t1
        => 12.845386198

        As be_within matcher works with the minus function :
        expect(t1).to be_within(1).of(t2)

        The “.second” is not necessary.

  • Lionel Tan

    Great explanation and solution to how to solve Time comparisons.

    I used to do it by casting it to a string like below:

    a, b = Time.now, Time.now

    a_to_s = a.strftime(‘%Y-%m-%d %H:%M:%S’)
    b_to_s = b.strftime(‘%Y-%m-%d %H:%M:%S’)

    a_to_s == b_to_s

  • http://blog.plicatibu.com/ Marcio Andrey Oliveira

    You may do the following (assuming t1 and t2 are Time instances)


    require 'date'

    t1.to_date == t2.to_date

  • Ahmad hamza

    Hi i m comparing time like this “if a.start_time<= client.start" but a.start_time has the value "1970-01-01 09:00:00 UTC" and "2000-01-01 09:00:00 UTC". How to change that a.start_time ? Any idea

  • Aleksandr Kunin

    Or just use t1.round, that by default (without arguments) returns new Time object without subseconds.

Want to get more of Railsware blog?

RSS FEED

We're always ready to help!

CONTACT US