謝謝Jignesh。在這裏,我分享你的發現和解決方案。
可能有一些gem覆蓋to_date
的實現,它可能會被錯誤地實現,並且這個被覆蓋的版本可能會被調用。
在我的情況的罪魁禍首是ruby-units
寶石
根本原因:ruby-units
寶石包括在應用程序的Gemfile中
問題分析:
的Gemfile
# Ruby-units overrides String class #to method, hence placed before Rails
gem "ruby-units" # Loads first and then rails is loaded
gem "rails", "3.0.11"
..
..
time.rb文件(紅寶石單元寶石基本代碼)
..
..
unless Time.instance_methods.include?(:to_date)
# :nocov_19:
# @return [Date]
def to_date
x=(Date.civil(1970,1,1)+((self.to_f+self.gmt_offset)/86400.0)-0.5)
Date.civil(x.year, x.month, x.day)
end
# :nocov_19:
end
..
..
比方說在UTC
時區即當前時間是 Wed, 11 Apr 2012 10:12:17 UTC +00:00
由ActiveSupport::TimeWithZone
實例表示。 從rails應用程序執行<TimeWithZone>.to_date
時,它返回 日期2012-04-10
這是不正確的。
上述不正確的行爲涉及罪魁禍首是由ruby-units
寶石
下面提供to_date
方法 的實現是示例程序來證明上述不正確的行爲。to_date
方法與ruby-units
gem實現的方法相同,不同的是方法中增加了一個參數,即date_time
,實現中的self
被參數 'date_time'取代。
樣品Ruby程序,以確認上述發現:
require 'rubygems'
require 'active_support/all'
class TestDT
def to_date(date_time)
#x=(Date.civil(1970,1,1)+((self.to_f+self.gmt_offset)/86400.0)-0.5)
x=(Date.civil(1970,1,1)+((date_time.to_f+date_time.gmt_offset)/86400.0)-0.5)
Date.civil(x.year, x.month, x.day)
end
end
tdt = TestDT.new
utc_time = Time.now.in_time_zone('UTC')
puts tdt.to_date(utc_time)
輸出(日期在寫這篇的時間爲週三,11 Apr 2012 08:35:12 UTC +00:00
):
$ ruby test_date_time.rb
2012-04-10
解決方案:
- 刪除0123中的
ruby-units
寶石或加載後軌寶石
- 解決辦法:不要執行
datetime.to_date
的,使用datetime.to_s.to_date
什麼是Time.zone的價值? – 2012-04-11 08:51:56
@FrederickCheung Time.zone return UTC – 2012-04-11 09:43:12
你調用'to_date'的'ActiveSupport :: TimeWithZone'對象的'zone'的輸出是什麼? – shime 2012-04-11 09:59:31