Skip to main content

Command Palette

Search for a command to run...

Avoid Microsecond Pitfalls When Comparing Times in Tests

How to compare time in testing in Ruby on Rails

Updated
3 min read
Avoid Microsecond Pitfalls When Comparing Times in Tests

If microsecond precision is not required when testing Time, DateTime, or ActiveSupport::TimeWithZone, use iso8601 to assert equality between different times. There are two ways to avoid test failures caused by execution delays:

  1. Use time.iso8601

  2. Use time.to_fs(:iso8601)

Comparing two DateTime values

For example, to compare two DateTime values maybe you can try to write it like this:

def test_question_answered_at_the_same_as_survey
   assert_equal question.answered_at, survey.answered_at
end

describe 'question#answered_at'
   it 'is the same as survey' do 
       expect(question.answered_at).to eq(survey.answered_at)
   end
end

This approach can cause issues if there are microsecond delays when saving values to the database.

There are several ways to address this issue.

Using .change

One option is to use .change to set microseconds to zero.

def test_question_answered_at_the_same_as_survey
   assert_equal question.answered_at.change(usec: 0), survey.answered_at.change(usec: 0)
end

describe 'question#answered_at'
   it 'is the same as survey' do 
       expect(question.answered_at.change(usec: 0)).to eq(survey.answered_at.change(usec: 0))
   end
end

Using .to_i

Alternatively, you can use the Time#to_i method, which truncates subseconds:

def test_question_answered_at_the_same_as_survey
   assert_equal question.answered_at.to_i, survey.answered_at.to_i
end

describe 'question#answered_at'
   it 'is the same as survey' do 
       expect(question.answered_at.to_i).to eq(survey.answered_at.to_i)
   end
end

Using .round

You can use from Ruby the Time#round where you can specific how to round the seconds value and doing Time#round is equivalent to Time#round(0) that means without milliseconds:

def test_answer_filled_at_the_same_as_survey  
  assert_equal(
    question.answered_at.round, 
    survey.answered_at.round
  )
end

describe 'question#answered_at' do
  it 'is the same as survey' do   
    expect(
      question.answered_at.round
    ).to eq(survey.answered_at.round
  end  
end

Another option only for RSpec will be be_within

In RSpec there is a specific helper called be_within which will convert Time to float and then check if the value is within a delta:

describe 'question#answered_at' do
  it 'is the same as survey' do   
    expect(question.answered_at.round).to be_within(1).of(survey.answered_at)
  end  
end

In Minitest there is assert_in_delta

A similar helper exists in Minitest called assert_in_delta that also transforms to float and then compare it if it is withing a delta:

def test_answer_filled_at_the_same_as_survey  
  assert_in_delta(
    question.answered_at,
    survey.answered_at,
    1.0
  )
end

Using .iso8601

I recommend using iso8601 for this comparison:

def test_question_answered_at_the_same_as_survey
   assert_equal question.answered_at.iso8601, survey.answered_at.iso8601
end

describe 'question#answered_at'
   it 'is the same as survey' do 
       expect(question.answered_at.iso8601).to eq(survey.answered_at.iso8601)
   end
end

In Rails, you can also use to_fs(:iso8601):

def test_question_answered_at_the_same_as_survey
   assert_equal question.answered_at.to_fs(:iso8601), survey.answered_at.to_fs(:iso8601)
end

describe 'question#answered_at'
   it 'is the same as survey' do 
       expect(question.answered_at.to_fs(:iso8601)).to eq(survey.answered_at.to_fs(:iso8601))
   end
end

Why use .iso8601 or .to_fs(:iso8601)

First, ISO8601 is a widely adopted standard, so its behavior is consistent across Ruby and Rails implementations.

Second, using time.iso8601 is more descriptive than time.change(usec: 0), making the comparison method clearer and supporting consistent conventions in the codebase.

Third, this approach allows you to compare with fixed time values as well:


assert_equal question.answered_at.iso8601, "2025-10-07T13:35:25+03:00"
expect(question.answered_at.iso8601).to eq "2025-10-07T13:35:25+03:00"

I know that someone might say well to understand what iso8601 does tyou have to know about it. But here I think it is a normal expectation for an web engineer to know about ISO8601 standard when working with time.

Of course you should choose the one that works best for you.


👉 If you like this article and want it in your inbox each week, subscribe to my newsletter. You’ll find ideas on Ruby, software development, software testing, building products and workshops, plus notes on creativity, tech trends, and whatever else sparks my curiosity.

👐 Want to improve your developer testing skills? Visit goodenoughtesting.com/articles to discover resources on testing for developers.

👉 Join my Short Ruby Newsletter for weekly Ruby updates and visit rubyandrails.info, a directory of Ruby learning content.

🤝 Connect with me on Linkedin, Bluesky, Ruby.social, , and Twitter, where I mostly post about Ruby and Ruby on Rails.

🎥 Follow my YouTube channel for short videos about Ruby and Rails.

More from this blog

All about code - Ruby and Rails technical content written by Lucian Ghinda

102 posts

I write here quick thoughts, ideas, tips, and learnings about programming, programmers, and building software. Most of my focus is on Ruby, Rails, Hotwire, and everything about web applications.