Ruby on rails 如何将Rails日期时间分辨率限制为微秒?

Ruby on rails 如何将Rails日期时间分辨率限制为微秒?,ruby-on-rails,datetime,rspec,Ruby On Rails,Datetime,Rspec,Rails支持分辨率为纳秒的DateTime,但我注意到这取决于应用程序运行的机器 在运行Mojave的MacBook上,Time.zone.now.strftime(“%N”)将始终输出一个以000结尾的9位数字(例如“122981000”)。这意味着在Mac上,分辨率仅限于微秒级 但是,在Linux上,相同的命令返回一个分辨率为纳秒的数字(例如,“113578523”) 当我使用rspec时,我的问题出现了,我需要比较一些DateTime值。 当我在Mac上开发时,测试会完美通过,但当我们的

Rails支持分辨率为纳秒的
DateTime
,但我注意到这取决于应用程序运行的机器

在运行Mojave的MacBook上,
Time.zone.now.strftime(“%N”)
将始终输出一个以
000
结尾的9位数字(例如
“122981000”
)。这意味着在Mac上,分辨率仅限于微秒级

但是,在Linux上,相同的命令返回一个分辨率为纳秒的数字(例如,
“113578523”

当我使用
rspec
时,我的问题出现了,我需要比较一些
DateTime
值。
当我在Mac上开发时,测试会完美通过,但当我们的CI(Travis)运行相同的测试时,它会失败如下:

       expected: 2019-04-09 19:14:27.214939637 -0300
            got: 2019-04-09 19:14:27.214939000 -0300
这里的问题是我们的数据库Postgres被限制在微秒之内,就像我的Mac一样,它不会失败。我将
DateTime
存储在数据库中,然后将其读回并与内存中的内容进行比较。数据库将舍入到微秒,因此比较失败

是否可以强制Rails以微秒的精度运行?

我的目的是不需要在每次测试中手动舍入或截断时间戳。

我以前遇到过这种情况,新创建的ActiveRecord对象在内存中创建/更新的字段上的精度为9位(在Travis linux VM上),这与Postgres中存储的精度不同(6位)。我遇到了同样的问题,这些测试在本地(macOS)通过,但在CI构建中失败

在过去,我曾黑客规范,以迫使对象重新加载工作,但作为你突出显示是丑陋的,因为你必须这样做,为每一个测试。最近我又遇到了同样的问题,但这次我创建了一个无法“重新加载”的服务对象,所以我开始尝试寻找更好的解决方案

这并不理想,因为它需要猴子修补时间类,但是,它工作得很好

module ForceTimePrecision
  def now
    super.round(6)
  end
end

Time.singleton_class.send(:prepend, ForceTimePrecision)

修补时间单例的机制(因为我不能直接覆盖Time.now)基于此答案

舍入,正如sgbett回答建议的那样,舍入有时会向上或向下舍入,因此在我的应用程序中不匹配。在我的应用程序中,我们不需要比秒更高的精度,因此我们添加了一个匹配器用于这种情况

RSpec::Matchers.define :eql_time do |expected|
    match do |actual|
      # Rails has more precision than postgres so datetime objects do not match unless
      # matched up to seconds
      expected.to_i == actual.to_i
    end
end

您可以在matcher中使用
be_并检查0.1秒的差异。另请参考,如果您不关心毫秒差,您可以在期望值的两侧执行to_s/to_i。
be_in
仍然是需要应用于每个比较时间戳的测试的解决方案。如果可能的话,我想找到一个只需要一次改变的解决方案