Rails 关于 rails 项目时区设置问题

naitnix · 2012年10月09日 · 最后由 boyishwei 回复于 2016年06月21日 · 12951 次阅读

最近在干活的时候发现一个问题,数据库里存入的时间总是比自己预期的时间多 8 个小时。 具体看代码:

controller:
              time_from =  DateTime.strptime("2012-10-09 21:00:00", '%Y-%m-%d %H:%M:%S')
              object.new(:time_from => time_from)
              object.save

说明:以上代码为 controller 中的代码,即希望存入数据库中的时间为 2012-10-09 21:00:00 但是实际存入的时间却是 2012-10-10 05:00:00,结果是真实存入的时间比自己预期的时间多了 8 个小时。 需要解决的问题 1: 想让这两个时间达到一致

当我在 console 中拿到该对象的时候,又有了问题:

object  = TimeSpecial.first
object.time_from  # => Tue, 10 Oct 2012 05:00:00 CST +08:00

说明:即把上面刚刚存入的数据取出来的时候,访问该对象的 time_from 属性的时候,得到的值是数据库中的值,并不是当初期望存入的值。 需要解决的问题 2:希望该值为当初希望存入的值

我的配置:application.rb 文件:

config.active_record.default_timezone = :local
config.time_zone = 'Beijing'    

我的数据库为 mysql,对应的时区为:

mysql>  show variables like '%time_zone%';
+------------------+--------+
| Variable_name    | Value  |
+------------------+--------+
| system_time_zone | CST    |
| time_zone        | SYSTEM |
+------------------+--------+

因为我需要在 controller 中做时间的对比,即: Time.now < object.time_from 类似这样的对比,但是因为时区问题,对比总是会有错误,这个问题要怎样解决呢,望各位大侠指点了

把 config.active_record.default_timezone 放到 config.time_zone 之后试试

@beiersi ,按照你的方法试了下,还是多了 8 个小时,没有起到作用

@naitnix 貌似 Datatime.strptime 不指定时区的时候默认时区是 0,看来需要指定一下时区

@naitnix DateTime.strptime("2012-10-09 21:00:00+8", '%Y-%m-%d %H:%M:%S%z') 这样貌似可以

#4 楼 @beiersi 你这思路不对,rails 会在存储数据库时采用 UTC 时间,然后取的时候再转换出来。所以 mysql 应当使用 UTC 存储。这里有一个参考: https://makandracards.com/makandra/646-how-rails-and-mysql-are-handling-time-zones

@lyfi2003 ,那我是不是可以理解为,我只要将 mysql 的时区设置为 UTC 就可以了呢?

#6 楼 @naitnix 嗯。也就是说你只关心 rails 表现的时候即可。要存储时间 你关注一下 Time.zone.now 这样的代码 而不是 Time.now.

@lyfi2003 @naitnix 我认为这跟数据库内的时区没有关系,而是 time_from 的时区和 app 时区不一致造成的。因为 rails 自动会去转换。所以现在只要正确设定 time_from 的时区即可。

#8 楼 @beiersi 嗯,意思一样,不过 rails 已经提供了 api . 见 zone

@lyfi2003 ,按照你说的,确实是,我不用去关心数据库里面到底是什么样的数据,只是我在 rails 里面拿出来用的时候,rails 会自动给我转换,所以我在做时间对比的时候也就没问题了。但是如果我需要做统计,统计到小时,这需要我直接用数据库里面的值,这个时候的值就跟真实值差 8 个小时了,这种情况有什么好的解决办法么?

#10 楼 @naitnix 在统计程序里把时区差值加上去不行吗?

把这两行去掉:

config.active_record.default_timezone = :local
config.time_zone = 'Beijing'    

全部使用 UTC 时间,就可以了。

@raecoo ,这样做是肯定没问题的,但是总觉得这样不好,每次还要特地加上时差,如果这段代码将来拿给别人来维护的话,别人可能不知到为什么

#10 楼 @naitnix 统计的时候先time_from.getlocal('+08:00')自己手动转换一下

#13 楼 @naitnix 直接从数据库取的话就使用 UTC 时间对比就行了,如果需要转换,用 rails 提供的zone 系列就可以了。


1.9.3-p194-perf :003 > a = Blog.new(title:'new',body:'new',add: Time.now)
 => #<Blog id: nil, title: "new", body: "new", add: "2012-10-10 02:41:13", created_at: nil, updated_at: nil> 
1.9.3-p194-perf :004 > Time.now
 => 2012-10-10 10:41:33 +0800 
1.9.3-p194-perf :005 > a
 => #<Blog id: nil, title: "new", body: "new", add: "2012-10-10 02:41:13", created_at: nil, updated_at: nil> 
1.9.3-p194-perf :006 > a.add
 => Wed, 10 Oct 2012 02:41:13 UTC +00:00 
1.9.3-p194-perf :007 > Time.zone
 => (GMT+00:00) UTC 

debug 一下还是很清晰的。 rails 3.2.8 ruby1.9

@xds2000 ,因为库里的时间比 Time.now 慢了 8 个小时,也就是说你这个例子中的 a 这个对象,应该是 2012-10-10 10:41:13 这个时间入库的,但是库里面却是 2012-10-10 02:41:13,那么如果我要统计,在 10 点到 11 点中有多少数据入库的话,这条记录就统计不到了啊,因为我统计的 sql 是直接写的,类似与这种:select count(*) from tables where date_format(add,'%Y-%-m-%d :%H') = '2012-10-10 10',如果用这种数据库级别的统计的话,会导致数据会有偏差的

好复杂。。

既然要统计,Time.now.to_i 转成数字,不是更有效率么?

timezone 正确配置顺序是:

config.time_zone = 'Beijing' config.active_record.default_timezone = :local

。。晕。居然可以连发三条。一样的。。

大 BUG 喔。。我打完字。按住 ctrl 敲了三次回车。就出现了三个一样的回复。。那我在页面刷新之前。敲 100 个。岂不是回复 100 个一样的内容喔。

OK,谢谢各位的良言,像@zfjoy520 说的,按照这个顺序就可以了,其中: config.time_zone = 'Beijing' 这个值是 rails 系统对显示时间的默认设置,对于中国地区来说,设置成 Beijing 就可以了。 config.active_record.default_timezone = :local 这个 default_timezone 是决定 active_record 对数据库交互的时区设置,也就是影响 created_at 和 updated_at 在数据库的记录时间,只有两个参数:utc 和:local,rails 初始化时默认是 utc,所以保存到数据库的时间是 utc 时间。

对于我刚才说的统计问题,为了达到既显示中国北京时间,有需要在数据库存储的时间为当前的北京时间,那么只要将 config.active_record.default_timezone 设置为 local 就可以了

created_at datetime NOT NULL, updated_at datetime NOT NULL,

估计你的 time_from 字段 不是 datetime 吧。我这边 mysql> show variables like '%time_zone%'; 跟你是一样的。

存起来的东东。是可读的 +---------------------+ | created_at | +---------------------+ | 2012-05-30 16:29:30 | +---------------------+

25 楼 已删除
boyishwei Rails 中的时区及时间问题 提及了此话题。 06月21日 16:43
需要 登录 后方可回复, 如果你还没有账号请 注册新账号