Rails とタイムゾーン
Published: 2023/4/19
Time クラスのタイムゾーン、 TimeWithZone のタイムゾーン、 DB に読み書きする datetime のタイムゾーンがある。
DB 自身も now()
などでタイムゾーンを持っていたりもする。
それらの個人的なまとめ。
Time クラスのタイムゾーン
Ruby が提供する Time
クラスは、 unix time 的なやつ。
タイムゾーンを考慮できて、 utc か OS タイムゾーンのどちらかをオブジェクトに設定可能。
タイムゾーンは hour など、時刻の一部を切り出すメソッドに影響する。
Time.now.hour
# => 12
Time.now.utc.hour
# => 3
ActiveSupport::TimeWithZone
Time オブジェクトのようなノリで、任意のタイムゾーンを扱えるようにした拡張的なクラス。
これに加えて、 Rails は config.time_zone
を設定できるようにしていて、ここにタイムゾーンを指定すると、 TimeWithZone まわりのデフォルトのタイムゾーンが、その指定されたものになるようになる。
# 例: 以下は、 OS は JST で、
#
# config.time_zone = 'Eastern Time (US & Canada)'
#
# した場合の挙動。
Time.now
# => 2023-04-19 13:07:56.213691 +0900
Time.current
# => Wed, 19 Apr 2023 00:07:58.307798000 EDT -04:00
Rails 中で unix time 的な時刻を扱いたいときには、 Time
よりもこちらの TimeWithZone
を利用する方が、一般的に推奨されている。
DB に読み書きする際のタイムゾーン
DB と時刻に関するデータをやりとりする際には、特定の UTC 時刻をどう表すかと、それをどう ruby に変換するかが問題になる。
ruby 側の Dto としては、これまで見てきたとおり、 Time も TimeWithZone も UTC 時刻を情報として持っているので、そのいずれかが指定されれば、 ActiveRecord はよろしく動ける。
DB 側では、DB として DateTime (without timezone) でデータを持っているか、 unix time でデータを持っているかで話が変わってくる。 (補足: created_at などは DateTime without timezone がデフォルト)
ここで、 rails は設定として、 config.activerecord.default_timezone
を :local
か :utc
で指定できるようになっている。
DateTime だった場合には、この default_timezone の datetime が DB に記録されているものとして ActiveRecord はクエリなどを組み立てる。
(メソッドの内部で unix time を構築する際に Time.local
を使うか Time.utc
を使うかのフラグである。)
これによって datetime も timestamp も unix time として取り扱え、 ActiveRecord はオブジェクトの読み出しの際には TimeWithZone が利用される。
おまけ: DB のタイムゾーン
DB も、 DB が動いているサーバーないしグローバル設定としての timezone を考慮して挙動が変わったりする関数(NOW()
)だったりデータ型だったりがある場合があるので、それはそれで注意が必要。
Tags: rails
関連記事
factory_bot と必須 association
2023/4/23
Elasticsearch-rails で接続先情報を設定する方法
2021/12/18
OpenAPI では rails のクエリパラメータの完全サポートはできない
2021/10/29
Rails.cache の動作をログに出力する方法
2021/9/22