比较ruby中相同的DateTime对象 – 为什么这两个DateTime.now不相等?

在rails应用程序中,我有以下forms的模型代码:

def do_stuff(resource) models = Model.where(resource: resource) operated_at = DateTime.now models.each { |model| some_operation(model, operated_at) } some_other_operation models, operated_at end def some_operation(model, operated_at) model.date_time_field = operated_at model.save end def some_other_operation(models, operated_at) models.each do |model| if model.date_time_field < operated_at # do something end end end 

在这种情况下,将始终执行some_other_operation的“do something”块。 更奇怪的是,如果我在没有所有已定义函数的控制台中设置它,则比较按预期工作。 例:

 > model = Model.first > time_var = DateTime.now > model.last_imported_at = time_var => Fri, 25 Oct 2013 21:14:06 +0000 > model.save => true > model.last_imported_at  false > model.last_imported_at == time_var => true 

最后,如果在some_other_operation我改为按以下方式进行比较:

 if model.date_time_field.to_i < operated_at.to_i # do something end 

只有在预期时才会达到“做某事”的阻止。 我怀疑这是因为to_i方法将删除DateTime对象上定义的秒的分数,而且每个方法的范围实际上将operated_at变量重新定义为DateTime.now 。 如果是这种情况,那么我想我的问题是如何强制每个范围不重新定义operate_at?

可能的线索; 保存和重新加载的行为会截断DateTime的seconds_fraction部分。 日期字段成为ActiveSupport::TimeWithZone的实例。 只是保存而不重新加载不会这样做; 真正的DateTime对象仍然存在。

 2.0.0-p195 :001 > dt = DateTest.create 2.0.0-p195 :002 > right_now = DateTime.now 2.0.0-p195 :004 > dt.created_at = right_now 2.0.0-p195 :005 > dt.created_at == right_now => true 2.0.0-p195 :006 > dt.save 2.0.0-p195 :007 > dt.created_at == right_now => true 2.0.0-p195 :008 > dt = DateTest.find(dt.id) 2.0.0-p195 :009 > dt.created_at == right_now => false 

编辑: 当然调用models.each将在那里加载模型然后由于延迟加载行为。 道具给另一个回答者。 作为实验,尝试将models设置为Model.where(resource: resource).to_a

您有三个单独的方法,上面定义了三个独立的operate_at局部变量。 局部变量仅限于定义它们的方法的范围。

您需要定义实例变量,这些变量在整个类中都存在。 例如,您可以:

 def Model attr_accessor :operated_at def do_stuff(resource) models = Model.where(resource: resource) operated_at = DateTime.now models.each { |model| some_operation(model, operated_at) } some_other_operation models, operated_at end def some_operation(model, operated_at) model.date_time_field = operated_at model.save end def some_other_operation(models, operated_at) models.each do |model| if model.date_time_field < operated_at # do something end end end end 

这将使您能够在所有类方法中访问operated_at。

我假设这个问题是由你使用的惰性范围引起的: models = Model.where(resource: resource)

models是一个代理集合,将在某些时候通过rails解析,并且可能在您不确切知道的情况下重新进行评估。

因此,当您更改属性并且在检查属性之前未reload对象时,它可能不是最新的。

DateTime.now不适用于与Database datetime对象进行比较。

例:

  1. 如果您在太平洋时区运行服务器,您将获得

DateTime.now – >星期五,2013年10月25日15:28:21 -0800 (十月的夏令时应该是UTC的-7小时,但不知何故,datetime.now总是从UTC给你-8)

  1. 我想如果你使用Time.zone.now而不是DateTime.now会给你正确的比较。

Time.zone.now – >星期五,2013年10月25日15:27:17 PDT -07:00