時間を表現する型
日付(2001年1月1日)だけを扱う型
「2001年1月1日」のように日付だけを表現する型を、
PostgreSQLはDATE型
として扱える。
RoRはDateクラス
として扱える。
時間(9:05)だけを扱う型
「9時5分」のように時間だけを表現できる型を、
PostgreSQLはTIME型
として扱える。
RoRはクラス
として存在しない。(日付をどうしても付けないといけない)
モデルの定義とRoRのクラス
:date
で定義したものはDateクラス
:time
で定義したものはTimeクラス
:datetime
で定義したものはActiveSupport::TimeWithZoneクラス
(以下ActiveSupport::TimeWithZoneクラス
はTimeWithZoneクラス
と呼ぶ)
RoRで基本的に使うクラス
モデルの定義とRoR型の関係より主にRubyソース内で使うこととなるRoRの型は次の3つ。
Dateクラス
, Timeクラス
, TimeWithZoneクラス
。
(この中に含まれないDateTimeクラス
は基本的に使わない)
TimeクラスとTimeWithZoneクラスで迷ったら
Timeクラス
とTimeWithZoneクラス
で迷ったらTimeWithZoneクラス
を使っておく。
日付を表した文字列
ISOで規定された表現
ISOでタイムゾーンと時間を同時に表現した書式が規定されているので、これを使う。
2001-01-01T09:05:00+09:00
(UTC+9 日本)
2001-01-01T09:05:00Z
(UTC+0 イギリス)
2001-01-01 09:05の表記
2001-01-01 09:05
(このようにタイムゾーンがないものをここでは no timezone
と呼ぶこととする)
文字列からクラスへの変換
文字列 to Dateクラス
'2000-01-01'.to_date
文字列 to Timeクラス
'2001-01-01T09:05:00+09:00'.to_time
文字列 to TimeWithZoneクラス
Time.zone.parse('2001-01-01T09:05:00+09:00')
クラスから年、月、日、時間、分、曜日を取り出す
ここではあえて
config.time_zone = 'Pacific Time (US & Canada)'
を設定した状態での動きを記載する。
Timeクラス
0> hoge = '2001-01-01T09:05:00+09:00'.to_time
=> 2001-01-01 09:05:00 +0900
0> hoge.year
=> 2001
0> hoge.month
=> 1
0> hoge.day
=> 1
0> hoge.hour
=> 9
0> hoge.min
=> 5
0> hoge.wday
=> 1
コンフィグで日本でないタイムゾーンを設定しているのに日本の時間でGET
している...
TimeWithZoneクラス
0> foo = Time.zone.parse('2001-01-01T09:05:00+09:00')
=> Sun, 31 Dec 2000 16:05:00 PST -08:00
0> foo.year
=> 2000
0> foo.month
=> 12
0> foo.day
=> 31
0> foo.min
=> 5
0> foo.wday
=> 0
(あれ? wdayでうまくとれない気がしたが気のせいか...)
コンフィグで設定した時間で取得(GET)している。
UTCとして取り出したい
Timeクラス
0> hoge = '2001-01-01T09:05:00+09:00'.to_time
=> 2001-01-01 09:05:00 +0900
0> hoge.utc
=> 2001-01-01 00:05:00 UTC
0> hoge.utc.class
=> Time
0> hoge.utc.hour
=> 0
.utc
でアクセスすれば、UTCの時間としてGETできる。
TimeWithZoneクラス
0> foo = Time.zone.parse('2001-01-01T09:05:00+09:00')
=> Sun, 31 Dec 2000 16:05:00 PST -08:00
0> foo.utc
=> 2001-01-01 00:05:00 UTC
0> foo.utc.class
=> Time
.utc
でアクセスすれば、UTCの時間としてGETできる。
このときクラスはTimeクラス
になっている。
クラス to 文字列
Timeクラス
0> hoge.iso8601
=> "2001-01-01T09:05:00+09:00"
なんで日本以外のタイムゾーン設定してるのに、+9:00で出るんだろう...
0> hoge.utc.iso8601
=> "2001-01-01T00:05:00Z"
TimeWithZoneクラス
0> foo.iso8601
=> "2000-12-31T16:05:00-08:00"
0> foo.utc.iso8601
=> "2001-01-01T00:05:00Z"
ハマらないために
+9:00
がついた日本時間で文字列が取得されたり、日本時間で.hour
が取得されたりで、ハマるので、全部UTC
として扱ったほうがよい。
'2015-09-06T01:00:00Z'.to_time.utc
0> hoge = '2015-09-06T01:00:00Z'.to_time.utc
=> 2015-09-06 01:00:00 UTC
0> hoge.iso8601
=> "2015-09-06T01:00:00Z"
クラス to 他クラス
TimeWithZone to Time
0> foo = Time.zone.parse('2001-01-01T09:05:00+09:00')
=> Sun, 31 Dec 2000 16:05:00 PST -08:00
foo.utc // UTCなTimeクラスへ
TimeWithZone to Date
0> foo = Time.zone.parse('2001-01-01T09:05:00+09:00')
=> Mon, 01 Jan 2001 09:05:00 JST +09:00
0> Date.new(foo.utc.year, foo.utc.month, foo.utc.day)
=> Mon, 01 Jan 2001
今回TimeやTimeWithZoneを生成する文字列に+9:00
のものを使ったが、設計段階で、文字列もすべて00Z
で表現できるようにしておいた方が、混乱を避けれる。
saveするときの挙動
DBへの保存のタイムゾーンは、
config.active_record.default_timezone
で設定。
デフォルトはUTC(イギリス)。
ということで、デフォルトで使った場合。
self.bar = Time.zone.parse('2001-01-01T09:05:00+09:00')