塩焼きブログ

塩焼きに関しての研究内容を公開しています

Railsでのタイムゾーンの動的変更とサマータイムの取り扱いについて

Railsでは自分でタイムゾーンのテーブルを作成し管理することも可能だが、time_zone_selectを利用すればタイムゾーンのリストを自動生成することができ、そこで生成された値をTime.zoneに与える事でタイムゾーンを動的に変更することができる。

<%= form_for @user do |f| %>
<%= f.label :username %>
<%= f.text_field :username %>
<%= f.label :time_zone %>
<%= f.time_zone_select :time_zone, nil, {:include_blank => true}, {class: "form-class"} %>
<%= f.label :password %>
<%= f.password_field :password %>
<%= f.submit %>
<% end %>

以上のフォームでユーザー作成時にタイムゾーンを保存し、ApplicationController:before_actionなどで設定するだけで、利用者ごとにタイムゾーンを切り替える機能を構築できる。

Time.zone = user.time_zone

ユーザーのタイムゾーンによってサイトの時間表示を切り替える場合は、データベースにUTCでデータが保存されていることが前提である。ローカル時間でデータを保存していた日本国内限定サイトを多言語に対応させる場合は、一旦データベース内のdatetimeを持つレコードを取り出し、-9時間してからアップデートをかける事で対応可能である。

Time.nowではなくTime.zoneを使う

Time.nowではローカル時間に依存する。多言語対応を行う場合はTime.zone.nowを使うようにする事で、ユーザーに応じた時間を取得するよう心がけ、データベースへは基本UTCで保存されているため、Time.utc.nowを使うというようにルールを統一する。少しややこしいと思うなら、application.rbconfig.time_zoneUTCにして、適宜ユーザーに応じたタイムゾーンに変換する仕組みとした方が混乱を避ける事ができて良いだろう。

Railsサマータイムについて

  • Railstime_zone_selectではGMTによる時差付きのリストが出力される
  • データ呼び出し時にUTCに時差を加えたローカル時間を出力し、時刻の末尾にUTCの時差が表示されるRailsではサマータイムを自動で計算してくれる。

例えばイギリスのロンドンからのユーザーがアクセスした時、サマータイム中に該当する時刻のデータはUTC+01:00で取り出され、そうでない時刻に該当するデータはUTC+00:00で取り出される。8月に作成したデータのcreated_atと12月に作成したcreated_atを出力すると下記のようにサマータイムが反映されて出力される。

2014-08-31 10:00:00 +0100 2014-12-01 09:00:00 +0000

余談だが、time_zone_selectで出力されるGMTリストはサマータイムによって時差が変わるということは無い。日本にはサマータイム制度が存在しないため、サマータイムの存在を忘れて多言語対応のサイトを構築していると「GMTのリストから(GMT+00:00) Londonを選択したのに、データを取り出すと01:00になってしまうので時間がずれているのでは」と思ってしまうかもしれないが、そのような事はない。