Ruby中DateTime的毫秒分辨率

SRo*_*mes 26 ruby postgresql activerecord datetime rails-postgresql

我有一个字符串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 
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

是否丢弃毫秒.

现在,有趣的是,created_at在Rails和Postgres中都显示毫秒.但是其他时间戳字段(happened_at如上所述)则没有.(也许Rails使用NOW()函数而created_at不是传入DateTime).

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

mu *_*ort 19

ActiveRecord应该保留数据库的完整精度,你只是没有正确地看它.使用strftime%N格式查看小数秒.例如,这样psql说:

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

和ActiveRecord说:

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

所以一切都在那里,你只需要知道如何看待它.

另请注意,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" 
Run Code Online (Sandbox Code Playgroud)

查看connection_adapters/column.rbActiveRecord源代码并检查string_to_time方法的作用.你的字符串将沿着fallback_string_to_time路径向下移动,并保留小数秒,尽可能接近.在其他地方可能会发生一些奇怪的事情,鉴于我在Rails源代码中看到的奇怪事情,尤其是数据库方面,我不会感到惊讶.我会尝试手动将字符串转换为对象,以便ActiveRecord可以将它们的手保持不动.


SRo*_*mes 9

改变m.happened_at = '2012-01-01T00:00:00.32323'.to_datetime上面的代码来m.happened_at = '2012-01-01T00:00:00.32323'解决问题,虽然我不知道为什么.

  • 请注意,`DateTime.now.to_s`不返回小数秒.我改为使用`DateTime.now.iso8601(6)`. (7认同)
  • 这个问题很疯狂,我刚刚失去了两个小时.谢谢答案. (2认同)