【问题标题】:Why do certain Time comparisons have counterintuitive results?为什么某些时间比较会产生违反直觉的结果?
【发布时间】:2015-04-12 05:27:21
【问题描述】:

在 Ruby 2.1.2 中,我可以成功地同时比较 Time.parseTime.utc 的结果,并返回预期的 true

Time.parse("2015-02-09T22:38:43Z") == Time.utc(2015, 2, 9, 22, 38, 43)
=> true

但是,当第二个值不是整数时,同样的比较会违反直觉地返回 false

Time.parse("2015-02-09T22:38:43.1Z") == Time.utc(2015, 2, 9, 22, 38, 43.1)
=> false

尽管第二个值仍然是整数并且仍然等价:

Time.parse("2015-02-09T22:38:43.1Z").sec
=> 43
Time.utc(2015, 2, 9, 22, 38, 43.1).sec
=> 43
Time.parse("2015-02-09T22:38:43.1Z").sec == Time.utc(2015, 2, 9, 22, 38, 43.1).sec
=> true

此外,相同方法的连续调用之间的比较结果为true

Time.parse("2015-02-09T22:38:43.1Z") == Time.parse("2015-02-09T22:38:43.1Z")
=> true
Time.utc(2015, 2, 9, 22, 38, 43.1) == Time.utc(2015, 2, 9, 22, 38, 43.1)
=> true

为什么会这样?这是一个错误,还是我遗漏了什么?

【问题讨论】:

  • 请重新措辞。这是误导/混淆。在您声称比较失败的地方,它并没有失败,它成功并返回false
  • 这似乎是一个纯 Ruby 问题,在这种情况下,您应该删除所有对 Rails 的引用,尤其是 Rails 标记。

标签: ruby time ruby-2.1


【解决方案1】:

Ruby 在比较时间时会比较小数秒和秒。由于某种原因,您的时间会收到不同的小数秒:

Time.parse("2015-02-09T22:38:43.1Z").subsec
# => (1/10)
Time.utc(2015, 2, 9, 22, 38, 43.1).subsec
# => (14073748835533/140737488355328)

【讨论】:

  • 听起来像通常的浮点恶作剧——43.1 无法准确表示。
  • 即精确。当比较两个只有“足够接近”(即浮点和时间值)时才有意义的数字时,您必须确保它们在可接受的范围内。
【解决方案2】:

我相信您遇到了精度问题。整数秒比较起作用的原因是整数的精度,Ruby 为您在解析后的版本上执行了.to_i

Time 类的基础是一个整数,它表示一个非常精确的整数,解析和显式值的处理方式可能不同,足以导致问题。如果亚秒级精度对您来说并不重要,那么最好比较秒:

Time.parse("2015-02-09T22:38:43.1Z").to_i == Time.utc(2015, 2, 9, 22, 38, 43.1).to_i

在上述情况下,您正在比较自 Unix 纪元(1970 年 1 月 1 日)以来的秒数

另一种选择是创建一个函数以在一定精度内进行两次比较。许多单元测试框架提供了该功能。本质上,如果 T1 == T2 在 0.1 秒内,就足够了。

进行“内部”比较的最简单方法如下:

def within(time1, time2, precision)
    return (time1 - time2).abs < precision
end

注意:以上内容适用于时间、浮点数和分数。

【讨论】:

  • 有人愿意评论为什么我的回答被否决了吗?它是正确的。 Time.parseTime.utc 方法在逻辑上相似,但由于精度和舍入问题具有不同的小数值。但是,如果您只需要 0.1 秒的粒度,那么如果您对此进行测试,它们将是等效的。
猜你喜欢
  • 2017-07-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-23
  • 2010-12-03
相关资源
最近更新 更多