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

Ruby 为什么某些时间比较会产生违反直觉的结果?,ruby,time,ruby-2.1,Ruby,Time,Ruby 2.1,在Ruby 2.1.2中,我可以成功地同时比较Time.parse和Time.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) =

在Ruby 2.1.2中,我可以成功地同时比较
Time.parse
Time.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

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

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

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

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

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

我相信你遇到了一个精确的问题。整数秒比较之所以有效是因为整数的精度,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
def内(时间1、时间2、精度)
返回(时间1-时间2)。abs<精度
结束

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

我认为您遇到了精度问题。整数秒比较之所以有效是因为整数的精度,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
def内(时间1、时间2、精度)
返回(时间1-时间2)。abs<精度
结束

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

请重新措辞。这是令人误解的。当您声称比较失败时,它不是失败,而是成功,并返回
false
。这似乎是一个纯粹的Ruby问题,在这种情况下,您应该删除对Rails的所有引用,尤其是Rails标记。请重新表述您的措辞。这是令人误解的。当你声称比较失败时,它不是失败的,它是成功的,并且返回
false
。这似乎是一个纯粹的Ruby问题,在这种情况下,你应该删除对Rails的所有引用,特别是Rails标记。听起来像是普通的浮点骗局-43.1不能准确地表示出来。精确当比较两个仅在“足够接近”(即浮点值和时间值)时才重要的数字时,你必须确保它们在可接受的范围内。听起来像是常见的浮点骗局-43.1无法准确表示。例如。精确当比较两个仅在“足够接近”(即浮点值和时间值)时才重要的数字时,您必须确保它们在可接受的范围内。有人想评论我的答案被否决的原因吗?这是正确的。
Time.parse
Time.utc
方法在逻辑上相似,但由于精度和舍入问题,它们的分数值不同。然而,如果0.1秒的粒度是您所需要的,那么如果您进行了测试,它们将是等效的。有人愿意评论我的答案被否决的原因吗?这是正确的。
Time.parse
Time.utc
方法在逻辑上相似,但由于精度和舍入问题,它们的分数值不同。然而,如果您只需要0.1秒的粒度,那么如果您进行了测试,它们将是等效的。