Ruby on Rails 时区的奇怪行为



存在属性为whenduration的任务模型。

create_table "tasks", force: true do |t|
  ...
  t.datetime "when"
  t.integer  "duration"
  ...
end

我编写了检查任务是否处于活动状态的方法,以便我可以在页面上显示它。这是活动方法:

  def active?
    if (self.when + self.duration) > Time.now
      true
    end
  end

我尝试在控制台中检查对象:

t.when + t.duration
=> Sun, 08 Sep 2013 01:01:00 UTC +00:00
DateTime.now
=> Sun, 08 Sep 2013 01:57:13 +0200
t.active?
=> true

这很true但我输入了 1:00 时间和 1 分钟duration我希望这不应该是真的。

似乎数据库中when列未保存在正确的时区,因此给出了不正确的结果。如何解决这个问题?

似乎当数据库中的列未保存在正确的时区时

1)Rails在将时间插入数据库之前会自动将时间转换为UTC时间(这是一件事),这意味着时间的偏移量为"+0000"。 这意味着,如果您将 8pm 的时间保存到数据库中,并且您的服务器位于偏移量为"+0600"的时区,则等效的 UTC 时间为下午 2 点,因此 2pm 将保存在数据库中。 换句话说,本地服务器的时间比 UTC 时间早 6 小时,这意味着当服务器时区晚上 8 点时,UTC 时区是下午 2 点。

2)当你比较日期时,ruby会考虑时区偏移量 - 换句话说,ruby将所有时间转换为相同的时区,然后比较时间。 下面是一个示例:

2.0.0p247 :086 > x = DateTime.strptime('28-01-2013 08:00:00 PM +6', '%d-%m-%Y %I:%M:%S %p %z')
 => Mon, 28 Jan 2013 20:00:00 +0600 
2.0.0p247 :087 > y = DateTime.strptime('28-01-2013 08:20:00 PM +7', '%d-%m-%Y %I:%M:%S %p %z')
 => Mon, 28 Jan 2013 20:20:00 +0700 
2.0.0p247 :088 > x < y
 => false 

如果只是比较两个日期时间对象的时间,则 x 小于 y。 但是,y 在偏移量为 +7 的时区中的时间为 8:20pm,这相当于偏移量为 +6 的时区中的时间 7:20pm。 因此,y 实际上小于 x。您需要将苹果与苹果进行比较,这意味着您需要在心理上比较已转换为相同时区的时间,以获得与红宝石/轨道相同的结果。

3) 您可以使用 rails utc() 方法将 Time.now 转换为 UTC 时间:

2.0.0p247 :089 > x = Time.now
 => 2013-09-07 8:00:00 +0600 
2.0.0p247 :090 > x.utc
 => 2013-09-07 02:00:00 UTC 

这就是 ruby 在将 Time.now 与 task.when + task.duration 进行比较之前所做的

4)您可能会发现使用所需的时间创建DateTime对象更方便:

DateTime.strptime('28-01-2013 08:00:00 PM +0', '%d-%m-%Y %I:%M:%S %p %z'

由于您可以将偏移量指定为零,因此不必创建预期转换为 UTC 时间的时间。

或者你可以使用 change() 方法,它会导致 offset() 在不转换时间的情况下发生变化:

2.0.0p247 :011 > x = DateTime.now
 => Sun, 08 Sep 2013 00:34:08 +0600 
2.0.0p247 :012 > x.change offset: "+0000"
 => Sun, 08 Sep 2013 00:34:08 +0000 
默认情况下,

ActiveRecord 以 UTC 格式存储时间戳。请参阅如何在 Rails 中更改活动记录的默认时区?用于更改默认时区。

您也可以使用 Time#in_time_zone 将 t.when 转换为您的时区,请参阅 http://api.rubyonrails.org/classes/ActiveSupport/TimeWithZone.html。

相关内容

  • 没有找到相关文章

最新更新