Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Microseconds not matching in Ruby and PG #32

Closed
algodave opened this issue Feb 6, 2017 · 2 comments
Closed

Microseconds not matching in Ruby and PG #32

algodave opened this issue Feb 6, 2017 · 2 comments
Assignees
Labels

Comments

@algodave
Copy link
Contributor

algodave commented Feb 6, 2017

Seems like Time#usec used in Chronomodel::Conversions#time_to_utc_string sometimes returns a different number than the one actually stored in PG.

This prevents pred and succ to be computed properly.

In the following example, I'm trying to fetch the most recent history record and its predecessor, but the pred method fails as it returns nil.

record = MyModel.find(123)
# got the record
most_recent = record.history.last
# got the history record
most_recent.valid_from.usec
# => 129625
most_recent.pred
# => nil

In order to check that a predecessor actually exists, I computed it "manually" like this:

computed_pred = 
  if record.history.count > 1
    record.history[record.history.count - 2]
  else
    nil
  end

This way, I got the history record and then I checked its valid_to's microseconds:

computed_pred.valid_to.usec
# => 129625

On the Ruby side, it is the same as most_recent record's valid_from. Where's the issue then? I checked on the PG side by executing the following query:

select validity from history.my_table where id=123 order by recorded_at;

and I got a result like this:

                       validity
------------------------------------------------------
 ["2012-03-10 00:00:00","2017-02-06 09:46:31.129626")
 ["2017-02-06 09:46:31.129626",)
(2 rows)

As you can see, microseconds differ in their last digit.

What happened?

Chronomodel was able to fetch the most_recent record because it doesn't use any timestamp in that query's conditions. But, when asking for most_recent.pred it passes most_recent.valid_from to Chronomodel::Conversions#time_to_utc_string in order to build the query condition, so '2017-02-06 09:46:31.129625' is passed to PG, and then no results are returned.

I am on the improve-amend-period branch with Ruby 2.3.3, PostgreSQL 9.4.9 and am using:

activerecord (5.0.1)
pg (0.19.0)
@algodave algodave added the bug label Feb 6, 2017
@pzac pzac assigned amedeo, vjt and lleirborras and unassigned pzac Feb 9, 2017
@vjt
Copy link
Contributor

vjt commented Feb 9, 2017

Problem identified. This code needlessly uses floating-point math causing rounding errors.

>> t = '2017-02-06 09:46:31.129626'
=> "2017-02-06 09:46:31.129626"
>> t =~ ISO_DATETIME
=> 0
>> $7
=> ".129626"
>> $7.to_f
=> 0.129626
>> $7.to_f * 1_000_000
=> 129625.99999999999
>> ($7.to_f * 1_000_000).to_i
=> 129625

Changing the regexp to capture only what is after the . and then using integer-only conversion removes the problem entirely.

Now working on a test case.

@vjt vjt closed this as completed in fe6ead3 Feb 9, 2017
@vjt
Copy link
Contributor

vjt commented Feb 9, 2017

@algodave please test and let me know, I will cut a release afterwards.

tagliala added a commit that referenced this issue Feb 27, 2024
This method was used in features that were removed (#268 and #271) and
the reason for converting ts values selected from the timeline query
is not explicitly documented in the commit history and appears to
be redundant (they are already timestamps)

After conducting manual tests on the `usec`s, it was determined that
the issue reported in issue #32 is no longer valid.
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
Projects
None yet
Development

No branches or pull requests

5 participants