Millisecond resolution of DateTime in Ruby

六月ゝ 毕业季﹏ 提交于 2019-11-29 02:24:10

问题


I have a string like 2012-01-01T01:02:03.456 that I am storing in a Postgres database TIMESTAMP using ActiveRecord.

Unfortunately, Ruby seems to chop off the milliseconds:

ruby-1.9.3-rc1 :078 > '2012-12-31T01:01:01.232323+3'.to_datetime
 => Mon, 31 Dec 2012 01:01:01 +0300 

Postgrs supports microsecond resolution. How can I get my timestamp to be saved accordingly? I need at least millisecond resolution.

(PS Yes I could hack in a milliseconds integer column in postgres; that kind of defeats the whole purpose of ActiveRecord.)

UPDATE:
The very helpful responses showed that Ruby's DateTime is not chopping off milliseconds; using #to_f shows it. But, doing:

m.happened_at = '2012-01-01T00:00:00.32323'.to_datetime
m.save!
m.reload
m.happened_at.to_f

Does drop the milliseconds.

Now, the interesting thing is that created_at does show milliseconds, both in Rails and Postgres. But other timestamps fields (like happened_at above) don't. (Perhaps Rails uses a NOW() function for created_at as opposed to passing in a DateTime).

Which leads to my ultimate question:
How can I get ActiveRecord to preserve millisecond resolution on timestamp fields?


回答1:


ActiveRecord should preserve the full precision from the database, you're just not looking at it properly. Use strftime and the %N format to see the fractional seconds. For example, psql says this:

=> select created_at from models where id = 1;
         created_at         
----------------------------
 2012-02-07 07:36:20.949641
(1 row)

and ActiveRecord says this:

> Model.find(1).created_at.strftime('%Y-%m-%d %H:%M:%S.%N')
 => "2012-02-07 07:36:20.949641000" 

So everything is there, you just need to know how to see it.

Also note that ActiveRecord will probably give you ActiveSupport::TimeWithZone objects rather than DateTime objects but DateTime preserves everything too:

> '2012-12-31T01:01:01.232323+3'.to_datetime.strftime('%Y-%m-%d %H:%M:%S.%N')
 => "2012-12-31 01:01:01.232323000" 

Have a look at connection_adapters/column.rb in the ActiveRecord source and check what the string_to_time method does. Your string would go down the fallback_string_to_time path and that preserves fractional seconds as near as I can tell. Something strange could be going on elsewhere, I wouldn't be surprised given the strange things I've seen in the Rails source, especially the database side of things. I'd try converting the strings to objects by hand so that ActiveRecord will keeps its hands off them.




回答2:


Changing m.happened_at = '2012-01-01T00:00:00.32323'.to_datetime in the code above to m.happened_at = '2012-01-01T00:00:00.32323' solves the problem, though I have no idea why.




回答3:


I ended up here when I was suffering from using the RVM provided binary Ruby 2.0.0-p247 on OS X (Mavericks) which was causing rounding to whole values of seconds when retrieving times from Postgres. Rebuilding Ruby myself (rvm reinstall 2.0.0 --disable-binary) solved the issue for me.

See https://github.com/wayneeseguin/rvm/issues/2189 which I found via https://github.com/rails/rails/issues/12422.

I recognise that this is not THE answer to this issue but I hope this note might help someone struggling with it.




回答4:


to_datetime does not destroy millisecond resolution of data - it's simply hidden because DateTime#to_s doesn't display it.

[1] pry(main)> '2012-12-31T01:01:01.232323+3'.to_datetime
=> Mon, 31 Dec 2012 01:01:01 +0300
[2] pry(main)> '2012-12-31T01:01:01.232323+3'.to_datetime.to_f
=> 1356904861.232323

That said, I suspect that ActiveRecord is mistakenly hiding that information when persisting the data; remember that it is database-agnostic, so it takes approaches that are guaranteed to work across all of its database targets. While Postgres supposed microsecond information in timestamps, MySQL does not, so I suspect AR selects for the lowest common denominator. I couldn't be sure without getting into the guts of AR. You may need a Postgres-specific monkeypatch to enable this behavior.



来源:https://stackoverflow.com/questions/14107354/millisecond-resolution-of-datetime-in-ruby

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!