ローカルタイムに関する設定
Rails3系からデータベースにはUTCで保存、取り出して扱う際に必要なタイムゾーンに変更するというのが基本的な考え方の様子。
タイムゾーンの設定はapplication.rbにて行えるが、主に関係する設定が2つある。
- config.active_record.default_timezone
- config.time_zone
config.active_record.default_timezone
データベースに保存する際のタイムゾーンを指定するディレクティブ。先ほど書いたようにRails3からはデータベースに時刻を保存する場合は基本的にUTCで保存するようになったみたいで、これをローカルタイムで保存するには以下のように設定すれば良い。
config.active_record.default_timezone = :local
config.time_zone
こちらが色々悩ましそうな感じで今確認出来たところだとActiveSupport::TimeZoneクラスの出力に影響を与える様子。試しに何も設定しない場合とtime_zoneをtokyoにした場合で色々出力してみると
設定しない場合
Time.zone # => (GMT+00:00) UTC
Time.zone.now # Mon, 24 Sep 2012 09:19:35 UTC +00:00
Tokyoにした場合
config.time_zone = 'Tokyo'
Time.zone # => (GMT+09:00) Tokyo
Time.zone.now #=> Mon, 24 Sep 2012 18:16:43 JST +09:00
とこの様に出力が変更されていることが確認できた。注意が必要なのはActiveSupport::TimeZoneを使うにはTime.zoneで処理を行う必要がありTime.nowのようにTimeで直接処理すると設定に関係なくローカルタイムで表示されてしまう点。
Time / Time.zoneの違い
Time.class # => Class (常にローカル扱い)
Time.zone.class # => ActiveSupport::TimeZone (config.time_zoneの設定に依存)
ということでユーザによってタイムゾーンを変える必要があるアプリケーションは
- config.time_zone = 'Tokyo' を設定する
- Time.zoneを常に使う (追記: ActiveRecordと併用する場合はto_s(:db)でUTCに変換 => DB登録時に更に時刻の差分を補正と2重に処理が走ってしまうので注意)
更に追記、config.time_zoneを変更してしまうとActiveRecordを利用する際に
- オブジェクトを生成したタイミングでタイムゾーンをUTCに合わせようとする
- Arelなどwhereをする際にカラムの値で指定する場合などでは合わせようとしない
という違いが発生してしまう。
created_at = "2012-09-01 00:00:00"
@example = Example.new(:created_at => created_at)
@example.created_at # => 2012-08-31-15:00:00
created_at = "2012-09-01 00:00:00"
Example.where(:created_at => created_at).to_sql # => SELECT `examples`.* FROM `examples` WHERE `examples`.`created_at` = '2012-09-01 00:00:00
なので、結果的には何も設定せずにユーザ毎に自前で処理するのが良いかもしれないです…
常にローカルタイムで良いアプリケーションは
- config.active_record.default_timezone = :localを設定する
- config.time_zone = 'Tokyo'
って感じが良いのだろうか?
Tips
データベース用のフォーマット変換する
Time.zone.to_s(:db)は使ってしまうと事故が起きそう…
Time.zone.now.to_s(:db) # UTCに自動的に変更される
Time.zone.now.strftime("%Y-%m-%d %H:%M:%S") # ローカルタイムのまま
Time.now.to_s(:db) # ローカルタイムのまま