Thanks for the response -- we use PostgreSQL which does store all six microsecond digits.
Jacob On 15/01/2010, at 15.41, Chris Cruft wrote: > I gave up on that kind of resolution when I found that MySQL doesn't > support it! I'll try to test the patch though. > > -Chris > > On Jan 14, 10:20 am, Jacob Lauemøller <[email protected]> > wrote: >> Hi all, >> >> The microsecond handling in >> ActiveRecord::ConnectionAdapters::Column#fast_string_to_time and >> ActiveRecord::ConnectionAdapters::Column#microseconds fail for some values. >> >> In slightly more than 1% of all possible 6-digit cases, writing a timestamp >> to a database column and then reading it back in results in a different >> value being returned to the program. >> >> So, for instance, saving the timestamp >> >> 2010-01-12 12:34:56.125014 >> >> and then loading it again from the database yields >> >> 2010-01-12 12:34:56.125013 >> >> The problem occurs when the value read is converted from string form to a >> Ruby timestamp, so it is largely database independent (the exception being >> drivers that override the methods, or databases that don't support >> timestamps at all). >> >> The underlying problem is the use of to_i to convert from floats to ints >> inside the affected methods. As you know, to_i simply truncates the result >> and in some cases this causes rounding errors introduced by inherent >> inaccuracies in the multiplication operations and decimal representation to >> bubble up and affect the least significant digit. >> >> Here's a simple test that illustrates the problem: >> >> converted = >> ActiveRecord::ConnectionAdapters::Column.send('fast_string_to_time', >> "2010-01-12 12:34:56.125014") >> assert_equal 125014, converted.usec >> >> This test case (and a similar one for #microseconds) fail on plain vanilla >> Rails 2.3.5. >> >> I guess the best solution would be to change the ISO_DATETIME regex used to >> extract the microsecond-part from timestamps to not include the decimal >> point at all and then avoid the to_f and subsequent floating point >> multiplication completely inside the failing methods. However, these regexes >> are defined as constants on ActiveRecord::ConnectionAdapters::Column::Format >> and therefore publicly available, so the impact of changing these is >> difficult to ascertain. >> >> A simpler solution is to use round() instead of to_i to convert from the >> intermediate floating point result to int. This works (I have verified that >> the precision is sufficient for all possible 6-digit cases) but is about 15% >> slower than the current method. A small price to pay for correctness, in my >> opinion. >> >> I have attached a tiny patch (against 2.3.5) that switches the code to using >> round() and a test case that verifies that the method works for a few >> problematic cases that fail without the patch. >> >> I have also created a Lighthouse ticket #3693: >> >> https://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/3... >> >> Could some of you please take a look and see if the patch is acceptable and >> maybe carry it into the code base? >> >> Cheers >> Jacob >> >> fix_microsecond_conversion.diff >> 4KViewDownload >> >> > -- > You received this message because you are subscribed to the Google Groups > "Ruby on Rails: Core" group. > To post to this group, send email to [email protected]. > To unsubscribe from this group, send email to > [email protected]. > For more options, visit this group at > http://groups.google.com/group/rubyonrails-core?hl=en. > >
-- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group. To post to this group, send email to [email protected]. To unsubscribe from this group, send email to [email protected]. For more options, visit this group at http://groups.google.com/group/rubyonrails-core?hl=en.
