🌊

Railsのタイムゾーン設定について

2021/05/22に公開

株式会社TECH LUCKという会社で代表兼エンジニアをしている齊藤です。
本記事は表題の通り、Railsのタイムゾーンで考慮しなければならないことが多くあったので備忘録として残しておきます。

Railsのタイムゾーン関連には2つの設定がある

Railsのタイムゾーン関連で調べてみると大まかに2つの設定がありました。

  • config.time_zone
  • config.active_record.default_timezone

この2つの設定をするだけなのに、考慮しなければならないことが多くありました。

まとめ(タイムゾーンを日本時間にしたい場合に設定すること)

  1. OSのタイムゾーン設定をAsia/Tokyoにする
    • ローカルのMacで開発していれば、おそらくTokyoの設定になっているので不要
    • Dockerなどを使っている場合には、UTCとなっているためDockerファイルやdocker-compose.ymlの設定でAsia/Tokyoにする
  2. config/application.rb内で、config.time_zone = 'Tokyo'を設定する
  3. config/application.rb内で、config.active_record.default_timezone = :localにする
  4. OSの再起動、rails serverの再起動で設定を反映させる

Railsの2つの設定の違い

2つの設定の違いは以下のようになっています。

設定項目 設定される内容
config.time_zone Rails自体のアプリケーションの時刻の設定
config.active_record.default_timezone DBを読み書きする際に、DBに記録されている時間をどのタイムゾーンで読み込むかの設定

Railsのタイムゾーンで考慮しなければならない設定

この記事を読む際に、以下のタイムゾーン設定が関係してくることを頭の片隅に入れておいてください。

  • OSのタイムゾーン設定
  • Railsのタイムゾーン設定(config.time_zone)
  • ActiveRecordでレコードを読み書きする際のタイムゾーン設定(config.active_record.default_timezone)

実際に試してみる

OSタイムゾーン:UTC、config.time_zone='UTC'config.active_record.default_timezone='UTC'

まずは、config.time_zoneconfig.active_record.default_timezoneもデフォルトのままでrails consoleで挙動を確認してみます。
ただし、実行環境のOSのタイムゾーン設定はUTCとしているので、ローカルで開発している場合にはタイムゾーン設定が違う可能性があるため注意が必要です。

rails console
Time.now
=> 2021-05-22 04:34:18.938170881 +0000

Time.current
=> Sat, 22 May 2021 04:34:20.861324049 UTC +00:00

User.create(name: 'test', email: 'test@test.com')
=> <User id: 4, name: "test", email: "test@test.com", created_at: "2021-05-22 04:36:00.738175000 +0000", updated_at: "2021-05-22 04:36:00.738175000 +0000">

user.created_at
=> Sat, 22 May 2021 04:36:00.738175000 UTC +00:00

実際のDBのレコードに保存されているcreated_atのタイムスタンプ
2021-05-22 04:36:00.738175
表示項目 表示されているタイムゾーン
Time.now UTC
Time.current UTC
User.createで表示されるcreated_at UTC
user.created_atで表示されるcreated_at UTC
実際のDBのレコードのタイムスタンプ UTC

すべてUTCで表示されています。(当たり前の結果ですね。)
では、config.time_zoneだけをconfig.time_zone='Tokyo'に変更してみるとどうなるでしょうか。

OSタイムゾーン:UTC、config.time_zone='Tokyo'config.active_record.default_timezone= :UTC

rails console
Time.now
=> 2021-05-22 04:40:15.267729046 +0000

Time.current
=> Sat, 22 May 2021 13:40:17.768190047 JST +09:00

user = User.create(name: 'test1', email: 'test1@test.com')
=> <User id: 4, name: "test", email: "test@test.com", created_at: "2021-05-22 04:36:00.738175000 +0000", updated_at: "2021-05-22 04:36:00.738175000 +0000">

user.created_at
=> Sat, 22 May 2021 13:36:00.738175000 JST +09:00

実際のDBのレコードに保存されているcreated_atのタイムスタンプ
2021-05-22 04:40:30.082069
表示項目 表示されているタイムゾーン
Time.now UTC
Time.current JST
User.createで表示されるcreated_at UTC
user.created_atで表示されるcreated_at JST
実際のDBのレコードのタイムスタンプ UTC

Time.currentuser.created_atの出力結果がJSTの時刻となっています。
それ意外はUTCとなっています。

Time.nowはOSのタイムゾーンの結果(この場合ではUTC)を返し、Time.currentはRailsアプリのタイムゾーンの結果(この場合ではJST)を返すため違う結果が返ってきます。

しかし、ActiveRecordの読み書きの設定はUTC(config.active_record.default_timezone= :UTC)なのに、user.created_atがJSTで表示されるのはなぜでしょうか?
これは、config.time_zoneの設定はActiveSupport::TimeWithZoneに影響するためです。
そのため、ActiveRecordのcreated_atの日時に関する表示は、config.time_zoneで設定したタイムゾーン(今回の場合JST)に変換されるためです。

次に、config.active_record.default_timezoneの設定を変更してみましょう。
この設定で気をつけることは、config.time_zoneとは違い:UTC:localの2つの設定しかサポートしていないことです。
ActiveRecordを読み書きする際に、:UTCと設定されていればUTC時刻として読み書きすることになり、:localと設定すると、OSのタイムゾーン設定と同じ形になります。
そのため今回の場合では、OSのタイムゾーン設定がUTCとなっているため、ActiveRecordの読み書きもUTCとなるはずです。

OSタイムゾーン:UTC、config.time_zone='UTC'config.active_record.default_timezone= :local

rails console
Time.now
=> 2021-05-22 05:01:03.079872846 +0000

Time.current
=> Sat, 22 May 2021 05:01:05.337906708 UTC +00:00

User.create(name: 'test2', email: 'test2@test.com')
=> <User id: 6, name: "test2", email: "test2@test.com", created_at: "2021-05-22 05:01:26.756013000 +0000", updated_at: "2021-05-22 05:01:26.756013000 +0000">

user.created_at
=> Sat, 22 May 2021 05:01:26.756013000 UTC +00:00

実際のDBのレコードに保存されているcreated_atのタイムスタンプ
2021-05-22 05:01:26.756013
表示項目 表示されているタイムゾーン
Time.now UTC
Time.current UTC
User.createで表示されるcreated_at UTC
user.created_atで表示されるcreated_at UTC
実際のDBのレコードのタイムスタンプ UTC

OSタイムゾーン:UTC、config.time_zone='UTC'config.active_record.default_timezone= :UTC
と同じ実行結果になっていることがわかります。(当然の結果ですね。)

config.active_record.default_timezone= :localはOSのタイムゾーン設定を引き継ぐので、config.active_record.default_timezoneの設定は:localのままにして、OSのタイムゾーンを変更して実行してみましょう。

OSタイムゾーン:Asia/Tokyo、config.time_zone='UTC'config.active_record.default_timezone= :local

rails console
Time.now
=> 2021-05-22 14:16:09.609170085 +0900

Time.current
=> Sat, 22 May 2021 05:16:12.199845378 UTC +00:00

user = User.create(name: 'test6', email: 'test6@test.com')
=> <User id: 10, name: "test6", email: "test6@test.com", created_at: "2021-05-22 05:16:24.630028000 +0000", updated_at: "2021-05-22 05:16:24.630028000 +0000">

user.created_at
=> Sat, 22 May 2021 05:16:24.630028000 UTC +00:00

実際のDBのレコードに保存されているcreated_atのタイムスタンプ
2021-05-22 14:16:24.630028
表示項目 表示されているタイムゾーン
Time.now JST
Time.current UTC
User.createで表示されるcreated_at JST
user.created_atで表示されるcreated_at UTC
実際のDBのレコードのタイムスタンプ JST

Time.nowはOSのタイムゾーンの結果を返すため、JSTが結果として返される形となります。
また、config.active_record.default_timezone= :localとなっているため、実際のDBのレコードのタイムスタンプがOSのタイムゾーンであるJSTとして保存されています。
ただし、user.created_atに関しては前述の通り、config.time_zoneがUTCとなっているため、ActiveRecordのcreated_atの日時に関する表示はUTCになっています。

では、すべてをJSTにしたい場合の設定をして確認してみましょう。

OSタイムゾーン:Asia/Tokyo、config.time_zone='Tokyo'config.active_record.default_timezone= :local

この設定により、OSのタイムゾーン設定、Railsアプリケーションのタイムゾーン設定、ActiveRecordで読み書きする際のタイムゾーン設定がJSTになります。
挙動を確認してみましょう。

rails console
Time.now
=> 2021-05-22 14:34:53.4952888 +0900

Time.current
=> Sat, 22 May 2021 14:34:56.058340301 JST +09:00

user = User.create(name: 'test7', email: 'test7@test.com')
=> <User id: 11, name: "test7", email: "test7@test.com", created_at: "2021-05-22 14:35:10.214590000 +0900", updated_at: "2021-05-22 14:35:10.214590000 +0900">

user.created_at
=> Sat, 22 May 2021 14:35:10.214590000 JST +09:00

実際のDBのレコードに保存されているcreated_atのタイムスタンプ
2021-05-22 14:35:10.214590
表示項目 表示されているタイムゾーン
Time.now JST
Time.current JST
User.createで表示されるcreated_at JST
user.created_atで表示されるcreated_at JST
実際のDBのレコードのタイムスタンプ JST

無事、すべてがJSTになっていることが確認できました。
めでたしめでたし。

参考記事

https://qiita.com/yoshinyan/items/011f2bce3b288b574949

https://qiita.com/joker1007/items/2c277cca5bd50e4cce5e

https://blog.cloud-acct.com/posts/u-rails-applicationrb-settings/

https://qiita.com/kodai_0122/items/111457104f83f1fb2259

https://qiita.com/aosho235/items/a31b895ce46ee5d3b444

Discussion