比较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对象进行比较。
例:
- 如果您在太平洋时区运行服务器,您将获得
DateTime.now – >星期五,2013年10月25日15:28:21 -0800 (十月的夏令时应该是UTC的-7小时,但不知何故,datetime.now总是从UTC给你-8)
- 我想如果你使用Time.zone.now而不是DateTime.now会给你正确的比较。
Time.zone.now – >星期五,2013年10月25日15:27:17 PDT -07:00