谢谢Jignesh。在这里,我分享您的发现和解决方案。
可能有一些 gem 覆盖了to_date
实现,它可能被错误地实现,并且这个被覆盖的版本可能会被调用。
就我而言,罪魁祸首是ruby-units
宝石
根本原因:ruby-units
应用程序的 Gemfile 中包含 gem
问题分析:
宝石文件
# 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 文件(ruby-units gem 代码库)
..
..
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
不正确的日期。
上述错误行为的罪魁祸首是gemto_date
提供的方法的实现ruby-units
以下是演示上述错误行为的示例程序。该方法与gemto_date
实现的方法相同,只是在方法中添加了一个参数,即实现中的 由参数“date_time”替换。ruby-units
date_time
self
用于确认上述发现的示例 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
解决方案:
- 移除
ruby-units
gemGemfile
或在 rails gem 之后加载它
- 解决方法:不要执行
datetime.to_date
,而是使用datetime.to_s.to_date