Change default_timezone of active record
在rails中,我首先使用下面的activerecord配置。
1 | config.active_record.default_timezone = :utc |
现在,我想使用本地时区,所以我将其更改为:
1 | config.active_record.default_timezone = :local |
问题是,我需要将date / datetime列中的所有现有数据转移到本地时区。
实现这一目标的最佳方法是什么?
<子>
为什么我必须这样做是因为我必须在本地时区进行聚合,例如:group =>'DATE(created_at)',GROUP BY DATE(created_at)将基于UTC,但我想聚合 在当地时区有一天。
我知道如何编写迁移文件来迁移某个日期时间列。 但是有很多这样的专栏,所以我正在寻求更好的解决方案。
子>
这很危险,但这是我在迁移中所做的事情:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | class MigrateDateTimesFromUTCToLocal < ActiveRecord::Migration def self.up # Eager load the application, in order to find all the models # Check your application.rb's load_paths is minimal and doesn't do anything adverse Rails.application.eager_load! # Now all the models are loaded. Let's loop through them # But first, Rails can have multiple models inheriting the same table # Let's get the unique tables uniq_models = ActiveRecord::Base.models.uniq_by{ |model| model.table_name } begin # Now let's loop uniq_models.each do |model| # Since we may be in the middle of many migrations, # Let's refresh the latest schema for that model model.reset_column_information # Filter only the date/time columns datetime_columns = model.columns.select{ |column| [ :datetime, :date, :time].include? column.type } # Process them # Remember *not* to loop through model.all.each, or something like that # Use plain SQL, since the migrations for many columns in that model may not have run yet datetime_columns.each do |column| execute <<-SQL UPDATE #{model.table_name} SET #{column.name} = /* DB-specific date/time conversion */ SQL end rescue # Probably time to think about your rescue strategy # If you have tested the code properly in Test/Staging environments # Then it should run fine in Production # So if an exception happens, better re-throw it and handle it manually end end end end |
我的第一个建议是强烈建议你不要这样做。你正在打开一个受伤的世界。那就是说,这就是你想要的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | class ShootMyFutureSelfInTheFootMigration def up Walrus.find_each do |walrus| married_at_utc = walrus.married_at walrus.update_column(:married_at, married_at_utc.in_time_zone) end end def down Walrus.find_each do |walrus| married_at_local = walrus.married_at walrus.update_column(:married_at, married_at_local.utc) end end end |
您可以将首选时区传递到DateTime#in_time_zone,如下所示:
1 2 | central_time_zone = ActiveSupport::TimeZone.new("Central Time (US & Canada)") walrus.update_column(:married_at, married_at_utc.in_time_zone(central_time_zone)) |
或者你可以离开它,Rails将使用你当前的时区。请注意,这不是您所在的位置,而是您的服务器所在的位置。因此,如果您在冰岛和上海有用户,但您的服务器位于加利福尼亚州,则每个"本地"时区都将是美国太平洋时间。
像很多其他人说的那样,你可能不想这样做。
您可以在分组之前将时间转换为其他区域,所有这些都在数据库中。例如,使用postgres,转换为Mountain Standard Time:
1 2 | SELECT COUNT(id), DATE(created_at AT TIME ZONE 'MST') AS created_at_in_mst FROM users GROUP BY created_at_in_mst; |
您必须更改数据库中的数据吗?您可以改为在当地时区显示日期。这有用吗:在Rails 3中将UTC转换为本地时间