我有一个像2012-01-01T01:02:03.456
这样的字符串,我使用ActiveRecord存储在Postgres数据库TIMESTAMP中。
不幸的是,Ruby似乎会缩短毫秒:
ruby-1.9.3-rc1 :078 > '2012-12-31T01:01:01.232323+3'.to_datetime
=> Mon, 31 Dec 2012 01:01:01 +0300
Postgrs支持微秒级分辨率。如何才能相应地保存我的时间戳?我需要至少毫秒的分辨率。
(PS是的,我可以在postgres中以毫秒整数列进行破解;这种方式会破坏ActiveRecord的整个目的。)
更新
非常有用的回答显示Ruby的DateTime
不砍掉毫秒;使用#to_f
显示它。但是,做:
m.happened_at = '2012-01-01T00:00:00.32323'.to_datetime
m.save!
m.reload
m.happened_at.to_f
是否会丢弃毫秒。
现在,有趣的是created_at
确实在Rails和Postgres中显示毫秒。但是其他时间戳字段(如上面的happened_at
)则没有。 (也许Rails对NOW()
使用created_at
函数而不是传入DateTime。
这导致了我的终极问题:
如何让ActiveRecord在时间戳字段上保留毫秒分辨率?
答案 0 :(得分:18)
ActiveRecord应该保留数据库的完整精度,你只是没有正确地看它。使用strftime
和%N
格式查看小数秒。例如,psql
说明了这一点:
=> select created_at from models where id = 1;
created_at
----------------------------
2012-02-07 07:36:20.949641
(1 row)
和ActiveRecord说:
> Model.find(1).created_at.strftime('%Y-%m-%d %H:%M:%S.%N')
=> "2012-02-07 07:36:20.949641000"
所以一切都在那里,你只需要知道如何看待它。
另请注意,ActiveRecord可能会为您提供ActiveSupport::TimeWithZone
个对象而非DateTime
个对象,但DateTime
也会保留所有内容:
> '2012-12-31T01:01:01.232323+3'.to_datetime.strftime('%Y-%m-%d %H:%M:%S.%N')
=> "2012-12-31 01:01:01.232323000"
查看ActiveRecord源中的connection_adapters/column.rb
并查看string_to_time
方法的作用。你的字符串将沿fallback_string_to_time
路径向下移动,并保留小数秒,尽可能接近。在其他地方可能会发生一些奇怪的事情,鉴于我在Rails源代码中看到的奇怪事情,尤其是数据库方面,我不会感到惊讶。我试着用手将字符串转换为对象,这样ActiveRecord就可以将它们从手中移开。
答案 1 :(得分:9)
将上面代码中的m.happened_at = '2012-01-01T00:00:00.32323'.to_datetime
更改为m.happened_at = '2012-01-01T00:00:00.32323'
解决了问题,但我不明白为什么。
答案 2 :(得分:3)
当我在OS X(Mavericks)上使用RVM提供的二进制Ruby 2.0.0-p247时,我结束了这里,当从Postgres检索时间时,这导致四舍五入到整数秒。我自己重建Ruby(rvm reinstall 2.0.0 --disable-binary
)为我解决了这个问题。
请参阅我https://github.com/wayneeseguin/rvm/issues/2189找到的https://github.com/rails/rails/issues/12422。
我认识到这不是这个问题的答案,但我希望这个说明可能有助于有人挣扎。
答案 3 :(得分:1)
to_datetime
不会破坏毫秒的数据分辨率 - 它只是隐藏,因为DateTime#to_s
不会显示它。
[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
那就是说,我怀疑ActiveRecord在保存数据时错误地隐藏了这些信息;请记住,它与数据库无关,因此需要保证在所有数据库目标中都能正常工作的方法。虽然Postgres在时间戳中假设微秒信息,但MySQL没有,所以我怀疑AR选择最低公分母。如果没有进入AR的内脏,我无法确定。您可能需要Postgres特定的monkeypatch来启用此行为。