Ruby中DateTime的毫秒分辨率

我有一个像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 

是否丢弃毫秒。

现在,有趣的是,在Rails和Postgres中, created_at确实显示毫秒。 但其他时间戳字段(如上面的happen_at)则没有。 (也许Rails对created_at使用NOW()函数而不是传入DateTime)。

这导致了我的终极问题:
如何让ActiveRecord在时间戳字段上保留毫秒分辨率?

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可以将它们的手保持不动。

在上面的代码m.happened_at = '2012-01-01T00:00:00.32323'.to_datetime更改为m.happened_at = '2012-01-01T00:00:00.32323'解决了问题,但我不知道为什么。

当我在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找到了该url 。

我认识到这不是这个问题的答案,但我希望这个说明可以帮助有人挣扎。

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来启用此行为。