#日時の扱い方 Ruby ActiveSupport::TimeZone
Rubyには日付や時刻を扱うためのDateやTimeといったクラスがあります。そのため、Rialsアプリケーションで日付や時刻を扱う際にもただこれらのクラスを使えばいいと思われるかもしれませんが、ひとつ課題があります。それは、タイムゾーンです。
例えば、Railsアプリケーションがデータベース内に、ある日時を保存するとしましょう。その日時を東京に住むユーザーが見たときは東京時間、シンガポールに住む人が見たときはシンガポール時間で表示した方が良いでしょう。このように、地域の時間に合わせた日時を表示する必要があるということです。そのため、Railsでは日時のデータをタイムゾーンとともに取り扱うことができるようになっている。
タイムゾーンとともに日時を扱うには、Timeの代わりにActiveSupport::TimeWithZoneクラスを用います。Railsが日時を扱う際(日時型のデータをデータベースから読むときや、created_atなどのタイムスタンプを記録する際)には、自動的にこのクラスが利用されます。
それでは、Railsコンソールを立ち上げて挙動を確認してみましょう。(※Rialsアプリケーションのコンソールで動作します。)
まず、現在有効なタイムゾーンを確認してみましょう。Time.zoneと売ってみてください。何も手を加えていないRailsアプリケーションでは次のように、"UTC"という名前を持つActiveSupport::TimeZoneオブジェクトが返されるはずです。これは、UTC(協定世界時)タイムゾーンを意味しています。
2.6.0 :013 > Time.zone
=> #<ActiveSupport::TimeZone:0x000000000a8e9568 @name="UTC", @utc_offset=nil, @tzinfo=#<TZInfo::DataTimezone: Etc/UTC>>
続いて、そのUTCタイムゾーンにおける現在時刻を表すオブジェクトを取得しましょう。それには、Time.zone.nowを実行します。
2.6.0 :003 > Time.zone.now
=> Fri, 04 Oct 2019 13:52:47 JST +09:00
Time.zone.nowは、ActiveSupport::TimeWithZoneクラスのオブジェクトとなっています。試しに、classメソッドを調べてみましょう。
2.6.0 :004 > Time.zone.now.class
=> ActiveSupport::TimeWithZone
確かにそのようになっていますね。
オブジェクトの作成日時を表すreated_atなどもActiveSupport::TImeWithZoneのオブジェクトとなっています。
##タイムゾーンの変更
タイムゾーンは「現在のタイムゾーン」に当たります。データベースからモデルオブジェクトを取ってくると、オブジェクト内のcreated_atやupdated_atは、Time.zoneで示されたタイムゾーンに対応する時間オブジェクトとなります。
したがって、もしもモデルのcreated_atなどを日本時間での時間オブジェクトとして取得したいのであれば、Time.zoneを日本時間に指定してからオブジェクトを取得すれば良いということになります。試しに、Time.zoneに日本時間を指定してみましょう。次のように、Time.zoneにAsia/Tokyoを代入してみてください。
2.6.0 :009 > Time.zone = 'Asia/Tokyo'
=> "Asia/Tokyo"
これで設定が変わるので、Time.zone.nowを実行すると、今度は日本時間での現在時刻が取得できます。
2.6.0 :010 > Time.zone
=> #<ActiveSupport::TimeZone:0x000000000a8d9e10 @name="Asia/Tokyo", @utc_offset=nil, @tzinfo=#<TZInfo::DataTimezone: Asia/Tokyo>>
2.6.0 :011 > Time.zone.now
=> Fri, 04 Oct 2019 14:19:30 JST +09:00
同様に、クラスのcreated_atも、日本時間のオブジェクトを取得できるようになりました。
2.6.0 :018 > User.first.created_at
=> Fri, 04 Oct 2019 02:14:57 UTC +00:00