zhouying23 发表于 2018-9-28 12:14:40

Rails+MySQL开发中的时间问题

  MySQL中的时区
  显示时区信息
  


[*]mysql> show variables like '%time_zone%';
[*]+------------------+--------+
[*]| Variable_name    | Value|
[*]+------------------+--------+
[*]| system_time_zone | CST    |
[*]| time_zone      | SYSTEM |
[*]+------------------+--------+
[*]2 rows in set (0.00 sec)
  

  设置时区信息
  +8:00是中国所在的时区,东八区。
  


[*]mysql> set time_zone = '+8:00';
[*]Query OK, 0 rows affected (0.00 sec)
  

  Rails中的时区
  rails默认就是写入utc时间,然后读取也是utc时间。
  设置config.time_zone只能保证写入数据库的时间是local,就是保证创建对象的时候created_at和updated_at使用设置的本地时间。
  但是读出来的时候还是有可能是utc时间,有可能需要在界面上转换的。
  rails推荐使用utc时间,这样就统一了,只是在界面显示的时候格式化为本地时间。
  


[*]rake time:zones:all #查看所有时区
[*]rake time:zones:local #查看本地时区
  

  默认情况
  我们使用
  


[*]rails g scaffold post title:string content:string
  

  生成一个model之后,打开【db/migrate/201200_create_posts.rb】文件看到下面的内容。
  


[*]class CreatePosts < ActiveRecord::Migration
[*]def change
[*]    create_table :posts do |t|
[*]      t.string :title
[*]      t.string :content
[*]
[*]      t.timestamps
[*]    end
[*]end
[*]end
  

  t.timestamps会帮我们在数据库中生成created_at和updated_at两个字段,这两个字段rails会自动赋值不用我们手动指定。
  

  在界面上添加post之后,打开log/production.log文件,会看到下面的内容。
  


[*]INSERT INTO `posts` (`category_id`, `content`, `created_at`, `picture`, `published`, `title`, `updated_at`, `url`) VALUES (1, 'post100', '2012-11-01 05:13:45', NULL, 0, 'post100', '2012-11-01 05:13:45','post100')
  

  如果没有看到这条sql语句,那么就是在config/applicaiton.rb中添加
  


[*]config.log_level = debug
  

  debug的级别会在日志中记录每个sql,方便调试。在发布到生产环境之后,修改这个级别信息。
  请注意created_at的值,明明是中国时间中午插入的记录,但是insert语句中的时间却是utc时间,落后八个小时,因为中国是东八区+8:00。
  插入数据库的值自然也就是这个utc时间。
  设置时区之后
  解决这个问题可以在config/application.rb文件中添加下面的配置。
  


[*]config.active_record.default_timezone = :local
[*]config.time_zone = 'Beijing'
  

  再次插入数据,打开log文件,就会发现时间变成了北京时间,插入数据库的也是北京时间。进入mysql -u root -p之后,查询的结果也是北京时间。
  在view文件中使用
  


[*]
  

  显示的结果是
  


[*]2012-11-01 13:39:26 +0800
  

  是没有问题的,但是多了时区+0800信息。
  要是使用
  


[*]
  

  显示的结果就是
  


[*]2012-11-01 05:39:26
  

  没有了+0800,但是时间又变成了utc时间了。
  使用
  


[*]
  

  就变成
  


[*]2012-11-01 13:39:26
  

  这下没有时区+0800信息,时间也是本地时间了。就是先转换为本地时间,然后在进行格式化。
  


[*]created_at.utc         #转换为utc时间
[*]created_at.localtime   #转换为local时间
  

  还有就是在rails console中有一点特别。
  


[*]1.9.3-p286 :013 > p=Post.last
[*]Post Load (0.3ms)SELECT `posts`.* FROM `posts` ORDER BY `posts`.`id` DESC LIMIT 1
[*] => #
[*]1.9.3-p286 :014 > p.created_at
[*] => Thu, 01 Nov 2012 13:39:26 CST +08:00
  

  大家注意到了吗,在p=Post.last之后查询的结果显示created_at的时间是utc时间,但是等你敲入p.created_at之后,显示的值就变成了本地时间。
  总结
  时区以及日期的格式化是每个程序员的必修课,就像字符串的各种处理一样重要,而且使用频率很高。
  rails默认就是写入utc时间,然后读取也是utc时间。
  设置config.time_zone只能保证写入数据库的时间是local,就是保证创建对象的时候created_at和updated_at使用设置的本地时间。
  但是读出来的时候还是有可能是utc时间,有可能需要在界面上转换的。
  rails推荐使用utc时间,这样就统一了,只是在界面显示的时候格式化为本地时间。
  对于任何应用来说,遇到时区问题,都应该考虑语言本身和存储本身,甚至是操作系统本身的时区设置和一些默认值,这样才能最终较好的解决时区问题。
  参考文献
  1.Convert local time to UTC in Rails
  2.Rails 3 default datetime format without UTC
  3.rails 有关时区的设置的问题
  4.Date Time Format in RUBY
  5.rails time format
  6.完美解决rails中国时区时间设置
  7.Time Zones in Rails 2.1
  8.MySQL时区设置
  9.Rails内置的时间格式化


页: [1]
查看完整版本: Rails+MySQL开发中的时间问题