タイムゾーン
Rubyのタイムゾーン
Ruby の 日時/日付/時間(時刻)を扱うクラスは、(Ruby実行環境を動作させている)システムのタイムゾーンを利用します。
Railsのタイムゾーン
Railsでは、(Railsアプリが稼働する)システムのタイムゾーンとは別にRailsアプリ内で利用するタイムゾーンを設定/参照できます。
なので、Railsには、システムのタイムゾーンとRailsアプリ内で利用するタイムゾーン、の2種類のタイムゾーン設定があります。
システムのタイムゾーンではなくRailsアプリ内で利用するタイムゾーンの利用が推奨されています。
Railsでは、config/application.rbにてconfig.time_zoneに値をセットすることで、Railsアプリ内で利用するタイムゾーンを設定できます。
config.time_zoneのデフォルト値はUTCです。
Railsで日時/日付/時間(時刻)を扱う際にはActiveSupportモジュールのTimeWithZoneクラスを利用することが推奨されています。
TimeWithZoneクラスはconfig.time_zone(Railsアプリ内で利用するタイムゾーン)を内部で参照しています。
Railsでは、ActiveSupportモジュールでTimeクラスが拡張されていて、staticメソッドTime.zone.メソッド名でTimeWithZoneクラスのstaticメソッドにアクセスできます。
Railsでは、ActiveSupportモジュールで Timeクラスが拡張されていて、インスタンスメソッドTime#in_time_zoneで、Timeオブジェクト(インスタンス)をTimeWithZoneオブジェクトに変換できます。
また、TimeWithZoneクラスのインスタンスメソッドTimeWithZone#to_tomeで、TimeWithZoneオブジェクト(インスタンス)をTimeオブジェクトに変換できます。
ActiveSupportモジュールでは、Rubyの他(Date etc)の日時/日付/時間(時刻)を扱うクラスも拡張されています。
DBのタイムゾーン
DBでは、(DBが稼働している)システムのタイムゾーンを利用しています。
DBのタイムゾーン=(DBが稼働している)システムのタイムゾーン です。
なので、DBにタイムゾーンは保存されません。
Railsでは、DBのタイムゾーンを(Railsアプリが稼働している)システムのタイムゾーンと合わせるか、UTC(協定世界時)に設定する必要があります(理由については後述しています)。
Railsのタイムゾーン ⇄ DBのタイムゾーン
Railsでは、config/application.rbにてconfig.active_record.default_timezoneに値をセットすることで、DBの読み書き時のDB(が稼働しているシステム)のタイムゾーンについて設定します。
config.active_record.default_timezoneには2つの値のみしかセットできません。
ActiveRecordで読み書きする際に、:UTCと設定していればDBのタイムゾーンをUTCとして読み書きすることになり、:localと設定していれば、DBのタイムゾーンを(Railsが稼働している)システムのタイムゾーンとして読み書きすることになります。
:UTCをセットした場合、DB(が稼働しているシステム)のタイム・ゾーンをUTCにしなくてはなりません。
:localをセットした場合、DB(が稼働しているシステム)のタイム・ゾーンと(Railsが稼働している)システムのタイムゾーンを一致させなくてはなりません。
config.active_record.default_timezoneのデフォルト値はUTCです。
ActiveRecordが、Railsのタイムゾーン ⇄ DBのタイムゾーンでの(タイムゾーンに合わせた)日時/日付/時間(時刻)の変換を(自動的に)行ってくれます。
システムのタイムゾーン
Railsが稼働しているシステムのタイムゾーン。
RailsアプリをOS直で稼働させている場合、
システムのタイムゾーン=OSのタイムゾーン、
OS上のDocker etcの仮想化環境のコンテナ上で稼働させている場合、
システムのタイムゾーン=コンテナのタイムゾーン、となります。
コンテナのタイムゾーンはホストOS(仮想化環境を動作させているOS)のタイムゾーンとは別に管理されています。
コンテナ定義で、タイムゾーンを設定しなければ、そのコンテナのタイムゾーンはデフォルトのUTCになります。(コンテナのタイムゾーン=コンテナに組み込まれているOSのタイムゾーン。)
Dockerの場合、DockerHubで配布されているコンテナ・イメージのタイムゾーンはUTC(デフォルト)であること多いです。
コンテナ・イメージのタイムゾーンの変更(方法)については別途調べてください。
バックエンド(サーバーサイド)のタイムゾーン
Railsアプリはバックエンドで動作するアプリなので、Railsアプリでは 、バックエンドのタイムゾーン=Railsアプリのタイムゾーン です。
フロントエンド(クライアントサイド)のタイムゾーン
フロントエンドには、ブラウザ、モバイル/デスクトップ アプリ、があります。
フロントエンドのタイムゾーンは、フロントエンドが動作しているシステムのタイムゾーンです。
フロントエンドでは、フロントエンドが動作しているシステム=OSです(例外はあるかもしれません)。
ブラウザのタイムゾーンは、Java Script を用いて取得できます。
フロントエンドのタイムゾーン⇄バックエンドのタイムゾーン
フロントエンドとバックエンドで連携していて、
フロントエンドとバックエンドでタイムゾーンが異なる(可能性がある/マルチ・タイムゾーン含む)場合、フロントエンド・バックエンド間で、タイムゾーンに合わせた日時/日付/時間(時刻)の変換を行う必要があります。
この変換は、フロントエンドで行う方法とバックエンドで行う方法があります。
フロントエンドで行う場合、バックエンドから取得する際+バックエンドに渡す際に日時/日付/時間(時刻)の変換を行うことになります。
フロントエンドのタイムゾーン⇄バックエンドのタイムゾーン⇄DBのタイムゾーン
バックエンドで行う場合、フロントエンドのタイムゾーンをバックエンドに渡して、バックエンドで、フロントエンドに送る際+フロントエンドから取得する際に日時/日付/時間(時刻)の変換を行うことになります。
Railsでは、フロントエンドから取得したタイムゾーンをTime.zoneにセットすることで、データベースに送る際+データベースから取得する際に
ダイレクトに、データベース・フロントエンド間の日時/日付/時間(時刻)の変換を行えます。
フロントエンドのタイムゾーン=バックエンドのタイムゾーン⇄DBのタイムゾーン
Time.zoneで取得できるタイムゾーンのデフォルト値は、config.time_zoneでの設定値です。
フロントエンドのタイムゾーンをバックエンドに渡す方法には、2種類あります。
一つめはCookieを利用する方法です。
フロントエンドでCookieに取得したタイムゾーンをセットし、バックエンドではCookieから取得します。
二つめは、HTTP通信を利用する方法です。
フロントエンドでバックエンドへのリクエスト時にHTTPヘッダーにタイムゾーンをセットし、バックエンドではフロントエンドからのリクエストのHTTPヘッダーから取得します。
旧来のWEBアプリでは、フロントエンド→バックエンド間でのHTTPヘッダーを介したタイムゾーンの伝達はできないので、Cookieを介してタイムゾーンの伝達を行うことになります。
バックエンドで、フロントエンドとの通信とは関係のない、バッチ処理etcを行っている場合、フロントエンドからのタイムゾーンの取得は行えないので、予めフロントエンド+バックエンドで、ユーザー毎?にタイムゾーンの情報を永続化しておき、それをバッチ処理etcで利用することが必要になります。
Cookieでの実装例
HTTP通信での実装例
フロントエンド
バックエンド
Railsのタイムゾーンについての良記事
上記を読んでから、下記を読むと、理解しやすいはずです。