Rails:JSON中的时间#to_f精度?

时间:2012-02-04 01:05:30

标签: ruby ruby-on-rails-3 json floating-point

我在Ruby 1.8.7上使用Rails 3.2.1和Jbuilder构建一个简单的JSON API(1.9.x可能对我有所帮助,但我的托管服务提供商只有1.8.7)。

由于API使用者期望时间戳为浮点数,我现在只对时间属性做一个简单的to_f

json.updated_at record.updated_at.to_f #=> 1328242368.02242

to_f导致精确损失。当客户端请求自给定时间点以来已修改的记录时,这会导致一些问题,因为SQL查询找到客户端用于引用的相同记录。即当尝试查找比上面的示例更“新”的记录时,SQL查询(例如updated_at > Time.at(1328242368.02242))返回相同的记录,因为updated_at的实际值比给定的时间戳更精确且更小。

实际上,record.updated_at.usec #=> 224250.022425秒。注意额外的小数。

因此,最佳地,时间戳应该是JSON,带有1个额外的小数,例如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,所以float 可以具有更高的精度。它会破坏JS兼容性(因此JSON规范)添加另一个数字(十进制或其他),因为JS浮动无法处理,我相信。所以也许我需要一种完全不同的方法......

1 个答案:

答案 0 :(得分:1)

在评论中进行审议之后,最佳选择似乎是monkeypatching ActiveSupport::JSON以使其BigDecimalNumeric s相同:

class BigDecimal
  def as_json(options = nil) self end #:nodoc:
  def encode_json(encoder) to_s end #:nodoc:
end

这会覆盖Rails团队决定在JSON解串器中防止序列化BigDecimal被解析为浮点数(并且丢失精度)而不支持十进制数。