为什么某些时间比较会产生违反直觉的结果呢?

时间:2015-02-11 17:59:40

标签: ruby time ruby-2.1

在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

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

2 个答案:

答案 0 :(得分:5)

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

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

答案 1 :(得分:-1)

我相信你遇到了一个精确的问题。整数秒比较的原因是由于整数的精度,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

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