4

我想要一个实例中的日期部分ActiveSupport::TimeWithZone。我为此使用to_date了函数,但它返回前一天的日期。

例如,如果 datetime 是2012-04-11 09:05:00 UTC,并且如果我调用to_date那么它会返回2012-04-10but 2012-04-11

另外我没有使用特定的时区(默认为 UTC)

应用程序正在运行Ruby 1.8.7并且Rails 3.0.2

谁能告诉我为什么它给出了错误的日期?如果有更好的方法从给定的(的实例)获取日期(的实例Date)部分,也请建议我DateTimeActiveSupport::TimeWithZone

编辑:这里也有人面临同样的问题http://pastebin.com/sn8ExZiQ

注意Time.zone退货'UTC'

4

1 回答 1

1

谢谢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-unitsdate_timeself

用于确认上述发现的示例 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

解决方案:

  1. 移除ruby-unitsgemGemfile或在 rails gem 之后加载它
  2. 解决方法:不要执行datetime.to_date,而是使用datetime.to_s.to_date
于 2012-04-11T11:45:14.217 回答