Floating point precision issues when comparing dates in ActiveRecord
I just run into a weird issue when comparing dates in Rails. In years of development, I think it’s one of the few times I’ve run accross floating point precission issues.
For a syncing engine with an iOS app, I’m looking for records on a Rails app where their updated_at
field
is newer than a parameter I’m sending.
My original code, in the controller, looked like this:
and I was calling this with the following URL: /products.json?since=1370362746.67886
.
The date corresponded to the last updated_at
date on the database, so it should have not returned any
object. To my surprise, I was still getting an object. Here’s the irb
session:
If you check the query that is being generated, you’ll see that the date is sent as
2013-06-04 16:19:06.678859
, even though the original timestamp is 1370362746.67886
.
What’s going on then? Of course, floating point precission issues!
Check this irb
session:
As you can see, the float representation of the last updated_at
value is the same I’m sending. However,
when using to_r
to create a Rational
, you can see the two numbers are slightly different.
Workaround
The workaround I settled for is to use Rational
instead of floats
when first converting the floating
point representation to a date.
Here’s the current version of the code:
And here’s an irb
session showing it working as expected:
It’s very important to note that the parameter you send to Rational
has to be a String
and not a
number, otherwise it will be coalesced into a float
and lose precision before creating
the new Rational
instance.