任务模型包含属性when
和duration
。
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
列未保存在正确的时区中,因此它会提供不正确的结果。如何解决这个问题?
答案 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
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。