rails – 在保存到服务器之前将DateTime转换为UTC

我不知道如何,但我的控制台和我的服务器有两个不同的DateTime.now时区。 如果我在控制台中运行DateTime.now,则返回以下内容:

Wed, 04 Dec 2013 14:27:23 -0500 

但是,我的任务模型中有以下内容:

 def self.already_expired where("time_frame < ?", DateTime.now) end 

上面代码的目标是在’time_Frame’是过去日期的任务上触发一些任务方法。 这是我调用方法的地方:

 task :change_it => :environment do puts "yo yo you yo you" @tasks = Task.already_expired @tasks.each do |task| puts "Kalabar" + task.inspect + "now time is:" + DateTime.now.to_s end end 

服务器日志显示如下:

 Task Load (1.2ms) SELECT "tasks".* FROM "tasks" WHERE (time_frame < '2013-12-04 17:25:37') Kalabar# now time is:2013-12-04T12:25:37-05:00 Kalabar#now time is:2013-12-04T12:25:37-05:00 Kalabar#now time is:2013-12-04T12:25:37-05:00 

因此,它将time_frame与’2013-12-04 12:25:37进行比较,即UTC。 但是,当我打印DateTime.now.to_s时,它会打印’2012-12-04 08:15:00’。

我想在进入数据库之前将所有内容转换为UTC。 我也不明白为什么它有两个不同的DateTime.now时区这是我的问题

  1. 为什么DateTime.now有两个不同的时区
  2. 在将时区保存到数据库之前如何将时区转换为UTC?

更新:

我将以下内容放在application.rb文件中:

 config.time_zone = 'Eastern Time (US & Canada)' 

现在,用户在东部时间输入日期时间,并将其存储为UTC时间。 所以现在正在将time_frame正确地与DateTime.now进行比较。 问题在于,如果我放入time_frame,它会把它放在东部时间。 我不确定最新情况。 它以UTC格式存储,但在东部时间打印。 这是危险/正确吗? 我在代码的任务块中添加了“put time_Frame”,如下所示:

 task :change_it => :environment do @tasks = Task.already_expired @tasks.each do |task| puts "Kalabar" + task.inspect + "now time is:" + DateTime.now.to_s puts "time_frame is:" + task.time_frame.to_s end end 

并输出:

 Kalabar#now time is:2013-12-04T15:27:22-05:00 time_frame is:2013-12-02 03:15:00 -0500 Kalabar#now time is:2013-12-04T15:27:22-05:00 time_frame is:2013-12-02 04:02:00 -0500 Kalabar#now time is:2013-12-04T15:27:22-05:00 time_frame is:2013-12-04 15:15:00 -0500 

所以,正如你所看到的,在数据​​库中它是UTC,但是当它把它放在东方时。 为什么这样做/是危险的?

这是activerecord的默认行为,所有时间都将以UTC格式保存到数据库中。 你不需要转换它。 无论何时初始化当前时间,它都会返回一个时间对象,这意味着无论时区如何,它都将指向特定时间。 无论你在不同的时区获得什么时间,如果你将其转换为UTC,都指向同一时间。 所以,我不认为找到当前时间应该有任何问题,因为任何时间将如何存储在相应的时间。

当您尝试使用字符串初始化时间对象(或通过传递DateTime属性)时,只会出现时区问题。 使用系统时区解析时间对象,而不是使用application.rb中设置的时区。 因此,在这种情况下,最好使用ActiveSupport时区对象解析时间。

您可以在config/application.rb设置自定义时区

 # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. # config.time_zone = 'Central Time (US & Canada)' 

1)DateTime.now返回一个DateTime obj,你可以把它转换成你想要的任何时区(它仍然是它),如果你尝试用ActiveRecord做任何操作,ActiveRecord将默认将DateTime obj转换为UTC然后做好工作。

2)在将任何日期时间保存到数据库之前,请确保它是DateTime obj,如果您获得的日期时间是字符串,并且您知道时区,则可以使用DateTime.parse将其转换为DateTime obj:

 irb(main):014:0> s = "2013-12-02 09:00:00 EST" => "2013-12-02 09:00:00 EST" irb(main):015:0> sdt = DateTime.parse(s) => Mon, 02 Dec 2013 09:00:00 -0500 

我不认为你在看2个时区。 数据库中的所有时间(由task.inspect )都是UTC。 你是正确的,当运行DateTime.now你会得到一个表示当前时区的时间的对象。 很酷的事情是ActiveRecord非常聪明,可以将该对象更改为UTC以用于实际的sql命令。 在控制台中尝试这个:

 Task.where("time_frame < ?", DateTime.now).to_sql 

它应该将DateTime.now转换为UTC表示,这样您就应该得到您期望的结果。 那样有用吗?