Railsのタイムゾーン設定について
株式会社TECH LUCKという会社で代表兼エンジニアをしている齊藤です。
DXプロジェクト、開発プロジェクト、Rails開発などでお困りごとがありましたら弊社HPからご相談をいただけますと幸いです。
以下のような問題に対応することが可能です。
- プロジェクトでRailsエンジニアが足りなくて困っている
- Railsのバージョンアップをしたいがノウハウ・リソースが足りなくて困っている
- オフショア開発をしているが、要件の齟齬やコード品質が悪いので改善したい
また、Railsエンジニアも募集しておりますので、興味がありましたら弊社HPからご連絡いただけますと幸いです。
前提
本記事は表題の通り、Railsのタイムゾーンで考慮しなければならないことが多くあったので備忘録として残しておきます。
Railsのタイムゾーン関連には2つの設定がある
Railsのタイムゾーン関連で調べてみると大まかに2つの設定がありました。
config.time_zoneconfig.active_record.default_timezone
この2つの設定をするだけなのに、考慮しなければならないことが多くありました。
まとめ(タイムゾーンを日本時間にしたい場合に設定すること)
- OSのタイムゾーン設定をAsia/Tokyoにする
- ローカルのMacで開発していれば、おそらくTokyoの設定になっているので不要
- Dockerなどを使っている場合には、UTCとなっているためDockerファイルやdocker-compose.ymlの設定でAsia/Tokyoにする
- config/application.rb内で、
config.time_zone = 'Tokyo'を設定する - config/application.rb内で、
config.active_record.default_timezone = :localにする - 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_zoneもconfig.active_record.default_timezoneもデフォルトのままでrails consoleで挙動を確認してみます。
ただし、実行環境のOSのタイムゾーン設定はUTCとしているので、ローカルで開発している場合にはタイムゾーン設定が違う可能性があるため注意が必要です。
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
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.currentとuser.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
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
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になります。
挙動を確認してみましょう。
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になっていることが確認できました。
めでたしめでたし。
参考記事
Discussion