Ruby on Rails时区奇怪的行为

时间:2013-09-08 00:07:05

标签: ruby-on-rails ruby timezone

任务模型包含属性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}}我输入了1:00时间和1分钟,我希望它不应该是真的。

似乎数据库中的duration列未保存在正确的时区中,因此它会提供不正确的结果。如何解决这个问题?

2 个答案:

答案 0 :(得分:1)

  

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

1) Rails会自动将时间转换为UTC时间,然后再将它们插入数据库(这是好的事物),这意味着时间的偏移量为“+” 0000“。这意味着如果您将8pm的时间保存到数据库,并且您的服务器位于偏移量为“+0600”的时区中,则等效的UTC时间为下午2点,因此下午2点将保存在数据库中。换句话说,您的本地服务器的时间比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 

如果只是比较两个Datetime对象的时间,则x小于y。但是,y在时区中的时间为晚上8:20,偏移量为+7,相当于时域中的时间为下午7:20,偏移量为+6。因此,y实际上小于x。你需要比较苹果和苹果,这意味着你需要在精神上比较转换到同一时区的时间,以获得与ruby / rails产生的结果相同的结果。

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 

在将Time.now与task.when + task.duration

进行比较之前,这就是ruby所做的

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 

答案 1 :(得分:0)

默认情况下,ActiveRecord以UTC格式存储时间戳。有关更改默认时区的信息,请参阅How to change default timezone for Active Record in Rails?

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