Ruby Rails:JSON中的精确时间?
我正在使用Rails 3.2.1和Ruby 1.8.7构建一个简单的JSON API(1.9.x可能对我有所帮助,但我的托管提供商只有1.8.7) 由于API使用者希望时间戳是浮动的,所以我目前正在对时间属性执行一个简单的Ruby Rails:JSON中的精确时间?,ruby,ruby-on-rails-3,json,floating-point,Ruby,Ruby On Rails 3,Json,Floating Point,我正在使用Rails 3.2.1和Ruby 1.8.7构建一个简单的JSON API(1.9.x可能对我有所帮助,但我的托管提供商只有1.8.7) 由于API使用者希望时间戳是浮动的,所以我目前正在对时间属性执行一个简单的操作: json.updated_at record.updated_at.to_f #=> 1328242368.02242 但是to_f会导致精度损失。当客户端请求自给定时间点以来已修改的记录时,这会导致一些问题,因为SQL查询会找到客户端用于引用的相同记录。也就是
操作:
json.updated_at record.updated_at.to_f #=> 1328242368.02242
但是to_f
会导致精度损失。当客户端请求自给定时间点以来已修改的记录时,这会导致一些问题,因为SQL查询会找到客户端用于引用的相同记录。也就是说,当试图查找比上述示例更“新”的记录时,SQL查询(例如,updated\u at>Time.at(1328242368.02242)
)返回相同的记录,因为updated\u at
的实际值比给定的时间戳更精确、更大
事实上,record.updated_at.usec#=>22425
或0.022425
秒。注意额外的小数点
因此,最佳情况下,时间戳应该用一个额外的小数点JSON化,例如1328242368.022425,但我找不到实现这一点的方法
updated_at.to_i #=> 1328242368 # seconds
updated_at.usec #=> 22425 # microseconds
updated_at.to_f #=> 1328242368.02242 # precision loss
# Hacking around `to_f` doesn't help
decimals = updated_at.usec / 1000000.0 #=> 0.022425 # yay, decimals!
updated_at.to_i + decimals #=> 1328242368.02242 # dammit!
我到处寻找设置默认浮点精度的方法,但是我被难住了。有什么想法吗
编辑:我应该补充一点,API使用者没有运行JavaScript,因此浮点可以具有更高的精度。添加另一个数字(十进制或其他数字)会破坏JS兼容性(从而破坏JSON规范),因为我相信JS float无法处理这个问题。所以也许我需要一个完全不同的方法 在评论中经过深思熟虑后,最好的选择似乎是monkeypatchingActiveSupport::JSON
,以使其处理BigDecimal
s与Numeric
s相同:
class BigDecimal
def as_json(options = nil) self end #:nodoc:
def encode_json(encoder) to_s end #:nodoc:
end
这推翻了Rails团队的决定,即防止序列化的BigDecimal
s在不支持十进制数的JSON反序列化程序中被解析为浮点数(并失去精度)。能否将时间作为字符串输出:“{updated_at.to_i}.{updated_at.usec}”
?(好吧,根据需要将前导零添加到usec
)是和否。如果我输出字符串,我可以做很多类似的事情。但我需要输出一个浮点。如果我生成一个字符串,然后对它运行到_f
,我回到了开始的地方:精度损失。你能输出大小数而不是浮点数吗?JSON库可能可以将它们视为数字。关闭但不关闭BigDecimal
将JSON'd作为字符串获取(尽管具有适当的精度)。如果Ito_f
aBigDecimal
实例,它将再次导致精度损失。。。我可能需要找到一种附加“原始”JSON的方法,这样我就可以使用BigDecimal
来获取字符串,并在不加引号的情况下输出它。似乎有点骇人听闻,但是…BigDecimal
仅作为to_s
回退支持是值得针对JSON库报告一个bug的。这是一个数字,应该编码为一。