存在属性为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: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。