ActiveSupport :: TimeWithZone#to_date返回错误的日期

时间:2012-04-11 04:13:20

标签: ruby ruby-on-rails-3 datetime

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

例如,如果日期时间为2012-04-11 09:05:00 UTC,并且我致电to_date,则会返回2012-04-102012-04-11

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

该应用程序正在Ruby 1.8.7Rails 3.0.2

上运行

任何人都可以告诉我为什么错误的日期?另请建议我是否有更好的方法来获取日期(Date)的一部分来自给定的DateTimeActiveSupport::TimeWithZone的实例)

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

注意Time.zone返回'UTC'

1 个答案:

答案 0 :(得分:1)

谢谢Jignesh。在这里,我将分享您的发现和解决方案。

可能有一些gem覆盖to_date实现,可能会被错误地实现,并且可能会调用此重写版本。

在我的案例中,罪魁祸首是ruby-units gem

根本原因ruby-units gem包含在应用程序的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文件(ruby-units gem codebase)

..
..

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 实例。 当我们执行<TimeWithZone>.to_date时,从rails应用程序返回 日期2012-04-10不正确。

上述错误行为涉及的罪魁祸首是to_date方法的实现 由ruby-units gem

提供

以下是演示上述错误行为的示例程序。 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

<强>解决方案:

  1. ruby-units移除Gemfile gem或在rails gem
  2. 之后加载它
  3. 解决方法:使用datetime.to_date
  4. ,而不是执行datetime.to_s.to_date