`
280862132
  • 浏览: 84029 次
  • 性别: Icon_minigender_1
  • 来自: 重庆
社区版块
存档分类
最新评论

时区与程序-Rails 分享

阅读更多
转自 http://cao7113.blog.sohu.com/147243545.html
刚接触rails时,有时看到插入数据库的created_at字段与本地时间不一致,未深究。最近几个项目集成时,又遇相关问题,本文为调查记录,相关点:
本地时间-即观察者使用的当地时间(按地理标准时区概念)
操作系统时区设置
程序(Rails/Java)时区设置
数据库(MySql)时间字段的时区标准/设置
相关资料:
概念:
UTC-世界标准时间
LT-本地时间
CST-Central Standard Time, time zone offset: utc-6 hours
CST is used during winter in these US states(CDT during summer)...
计算机时间:主板上有个时钟发生器,用于计时。可通过CMOS设置时间(硬件时间)。Windows和Linux/Unix/Mac对硬件时间的理解不同,前者把它理解为LT(含时区值),后者理解为UTC,系统显示的时间是累加时区后的时间,网上很多人装双系统遇到时间不一致,就是这个原因。系统开机时读取硬件时间,关机时将对应值重新写入。
OS上的软件,一般都基于OS的时区设置,有些允许独立设置,如MySql,以支持世界各种时间变化,存储的时间字段也基于此时区设置。
Rails程序中的时区概念只是其间转换的工具(程序控制级别)
MySql:

MySQL 时区默认是服务器时区
可以通过以下命令查看
SQL代码

   1. mysql> show variables like '%time_zone%';  
   2. +------------------+--------+  
   3. | Variable_name    | Value  |  
   4. +------------------+--------+  
   5. | system_time_zone | CST    |   
   6. | time_zone        | SYSTEM |   
   7. +------------------+--------+  
   8. 2 rows in set (0.00 sec)  

可以通过修改my.cnf
在 [mysqld] 之下加
default-time-zone=timezone
来修改时区。如:
default-time-zone = '+8:00'
改了记得重启msyql喔!
另外也可以通过命令 set time_zone = timezone
比如北京时间(GMT+0800)
set time_zone = '+8:00';

Rails:
rails时区相关的rake tasks: time:zones:all/us/local
caoruijian@caoruijian-desktop:$ rake --tasks time:
(in /home/caoruijian/Aptana RadRails Workspace/web)
rake time:zones:all    # Displays names of all time zones recognized by the Rails TimeZone class, grouped by offset.
rake time:zones:local  # Displays names of time zones recognized by the Rails TimeZone class with the same offset as the system local time
rake time:zones:us     # Displays names of US time zones recognized by the Rails TimeZone class, grouped by offset.
rails相关类:TimeZone(2.1版本后),timezone是rails2.1后新加的特征,并对ruby的Time做了扩展
Time.zone可以查看时区,Time.zone=可以设置
Time.now显示本地时区的时间值

项目可能遇到的一个问题是:在rails中看到的是本地时间(如北京时间),利用Model.create方式存入数据库(Mysql)后看到的是UTC时间(早八个小时),完成的一个测试实验如下:
环境:
OS: Ubuntu, Timezong: Shanghai(同Beijing,东8区)
Rails: environment.rb中设置config.time_zone = 'Beijing'#UTC
MySql: my.cnf中设置default-time-zone = '+8:00'(现在作用还不明)
操作:在rails的action中调用User.create往数据库表自动插入一条记录,现在为早上09:24左右(系统显示的本地时间),rails生成的Sql为:
Processing TestController#test (for 127.0.0.1 at 2010-03-31 09:24:20) [GET]
  \u001B[4;36;1mUser Columns (0.6ms)\u001B[0m   \u001B[0;1mSHOW FIELDS FROM `users`\u001B[0m
  \u001B[4;35;1mSQL (0.0ms)\u001B[0m   \u001B[0mBEGIN\u001B[0m
  \u001B[4;36;1mUser Create (0.9ms)\u001B[0m   \u001B[0;1mINSERT INTO `users` (`name`, `created_at`, `updated_at`) VALUES(NULL, '2010-03-31 01:24:20', '2010-03-31 01:24:20')\u001B[0m
  \u001B[4;35;1mSQL (34.9ms)\u001B[0m   \u001B[0mCOMMIT\u001B[0m.
可见,rails在往数据库发送数据前就做了某些转换,实验中将Beijing时区的时间转换为UTC的啦。可见问题出在rails的ActiveRecord的转换机制上,那究竟是怎么回事呢?网搜后看到有人设置了:
config.active_record.default_timezone = 'Beijing'#:local (environment.rb中)
呵呵,实验后果然看起来正常啦!问题应该是ActiveRecord默认使用UTC时区时间,默认会在你设置的时区和UTC间转换。由此更能体会到ActiveRecord作为程序和数据库间连接纽带的作用
源码解析:(rails-2.3.4/lib/initialize.rb Rails::Initializer#initialize_time_zone)
    # Sets the default value for Time.zone, and turns on ActiveRecord::Base#time_zone_aware_attributes.
    # If assigned value cannot be matched to a TimeZone, an exception will be raised.
    def initialize_time_zone
      if configuration.time_zone
        zone_default = Time.__send__(:get_zone, configuration.time_zone)

        unless zone_default
          raise \
            'Value assigned to config.time_zone not recognized.' +
            'Run "rake -D time" for a list of tasks for finding appropriate time zone names.'
        end

        Time.zone_default = zone_default

        if configuration.frameworks.include?(:active_record)
          ActiveRecord::Base.time_zone_aware_attributes = true
          ActiveRecord::Base.default_timezone = :utc #呵呵,找到啦!
        end
      end
    end

那前文提到的MySql时区设置看起来为啥没起作用呢?问题还在于自己的理解上,default-time-zone = '+8:00',只在数据库级别上使用,并将任何输入作为该时区的时间值进行相关时间操作,跟这里要说的问题没什么关系
以上为临时记录,待进一步整理/更新,可能涉及的相关问题有:

    * rails时间/时区机制与原理,当使用ActiveRecord时对数据库时间的影响?
    * 当设定了某一时区时,对rails时间函数/时间比较逻辑的影响,如Time.now, Time.zone.now分别是那个时间?编写程序时是否要有时区意识,是否要修改遗留代码?
    * 系统如何处理多时区/地区/语言问题,更复杂的设置?可能关系到服务器上程序的国际/区域化管理
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics