Help us understand the problem. What is going on with this article?

ついにRoRの日付の闇を払った

More than 3 years have passed since last update.

時間を表現する型

日付(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')

self.bar:datetimeで定義したもの。とした場合、DB内では、
Screen Shot 2015-09-08 at 08.33.28.png
このように表現される。

shingo-nakanishi
https://www.clear-lesson.com/
https://www.clear-lesson.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした