【问题标题】:ActiveSupport::TimeWithZone#to_date returns wrong dateActiveSupport::TimeWithZone#to_date 返回错误的日期
【发布时间】:2012-04-23 09:21:08
【问题描述】:

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

例如,如果日期时间是2012-04-11 09:05:00 UTC,如果我调用to_date,那么它返回2012-04-10,但返回2012-04-11

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

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

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

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

注意Time.zone 返回'UTC'

【问题讨论】:

  • Time.zone 的值是多少?
  • @FrederickCheung Time.zone 返回 UTC
  • 你调用to_dateActiveSupport::TimeWithZone对象的zone的输出是什么?
  • @shime 它返回#<ActiveSupport::TimeZone:0xb7565fb0 @tzinfo=#<TZInfo::TimezoneProxy: Etc/UTC>, @utc_offset=nil, @name="UTC", @current_period=nil>

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


【解决方案1】:

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

可能有一些 gem 覆盖了 to_date 实现,它可能被错误地实现,并且这个被覆盖的版本可能会被调用。

就我而言,罪魁祸首是ruby-units gem

根本原因ruby-units gem 包含在应用程序的 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 代码库)

..
..

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

上述错误行为的罪魁祸首是to_date方法的实现 由ruby-unitsgem提供

以下是演示上述错误行为的示例程序。 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. Gemfile 中删除ruby-units gem 或在rails gem 之后加载它
  2. 解决方法:不要执行 datetime.to_date ,而是使用 datetime.to_s.to_date

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-19
    • 2012-10-08
    相关资源
    最近更新 更多