2013-10-25 86 views
4

在Rails應用程序,我有如下形式的型號代碼:在ruby中比較相同的DateTime對象 - 爲什麼這兩個DateTime.now不相等?

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的「有所作爲」塊就一定會執行,在這種情況下。更奇怪的是,如果我在控制檯中設置了沒有所有已定義函數的情況,則比較將按預期工作。例如:

> 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 < time_var 
=> 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用於每個方法的範圍。如果是這樣的話,那麼我想我的問題是我如何強制operated_at不爲每個範圍重新定義?

+0

這可能是因爲保存的行爲該模型會導致DateTime的'seconds_fraction'部分被截斷。 (雖然我還沒有證實)。 – struthersneil

+0

對不起,rails新手,我面對這類問題,只是想知道'localtime'或'timezone'對這種情況有影響嗎? – ksugiarto

回答

3

可能的線索;保存和重新加載的行爲會截斷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

+0

截斷部分是正確的答案。謝謝! – mattmattmatt

0

我認爲這個問題是由於您使用懶惰範圍:models = Model.where(resource: resource)

模式是代理的收集和將鋼軌在某些時候可以解決,沒有你確切地知道可能會被重新評估。

因此,當您在檢查屬性之前更改屬性並且您沒有reload對象時,它可能不是最新的。

+0

嘿謝謝你的回答。如預期的那樣,將DateTime對象轉換爲整數使得比較爲真;除非我誤解,否則這意味着這個問題不在'date_time_field'引用模型的一個較舊的,未更新的版本,而是多個單獨(稍微不同)的'DateTime.now'是當只有一個實例是打算使用的。 – mattmattmatt

1

您有三種單獨的方法,上面定義了三個獨立的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 

這將使您能夠在所有類方法中訪問operate_at。

0

DateTime.now無法與Database datetime對象進行比較。

例子:

  1. 如果服務器在太平洋時區運行,你會期望得到

    日期時間。現在 - > 週五,2013年10月25日15:28:21 -0800

(十月的夏令時應該是從UTC的-7小時,但不知怎的,datetime.now總是給你-8從UTC)

  1. 我想,如果你使用Time.zone.now代替DateTime.now會給你正確的比較。

    Time.zone.now - > 週五,2013年10月25日15點27分17秒PDT -07:00

相關問題