rails/rails — pull request #7352 by aripollak (2012-08-14 21:13:42+00:00)
Title: Fix occasional microsecond conversion inaccuracy

This patch was originally submitted by Logan Bowers in https://rails.lighthouseapp.com/projects/8994/tickets/4498-rails-loses-precision-when-deserializing-timestamps-from-postgresql, but I've shortened the test case significantly and I can reliably reproduce it.

In psql, run this:

CREATE TABLE tmps (id serial primary key, atime timestamp with time zone );

Then open up rails console and run this:

class Tmp < ActiveRecord::Base; end

time = Time.at(1344803062, 129346).utc
t = Tmp.create!({atime: time}, without_protection: true)
puts "Original time: " + time.strftime('%s.%N')
puts "Retrieved time: " + t.reload.atime.strftime('%s.%N')
puts "Raw time from DB: " + t.atime_before_type_cast

I get the following results without the patch:

1.9.3p194 :005 > class Tmp < ActiveRecord::Base; end
1.9.3p194 :007 > time = Time.at(1344803062, 129346).utc
=> 2012-08-12 20:24:22 UTC
1.9.3p194 :008 > t = Tmp.create!({atime: time}, without_protection: true)
(0.1ms) BEGIN
SQL (0.8ms) INSERT INTO "tmps" ("atime") VALUES ('2012-08-12 20:24:22.129346') RETURNING "id"
(2.6ms) COMMIT
=> #
1.9.3p194 :009 > puts "Original time: " + time.strftime('%s.%N')
Original time: 1344803062.129346000
1.9.3p194 :010 > puts "Retrieved time: " + t.reload.atime.strftime('%s.%N')
Retrieved time: 1344788662.129345000
1.9.3p194 :011 > puts "Raw time from DB: " + t.atime_before_type_cast
Raw time from DB: 2012-08-12 20:24:22.129346+00

Note that the DB says there are .129346 seconds, but Ruby says it's .129345 instead. With the patch, the times are all in sync.
This diff should also apply cleanly to 3.2.

CC: @tenderlove, @rafaelfranca