Rubyでは日付(yyyymmdd)を扱うためにDate
クラス、時刻(yyyymmdd hh:mm:ss)を扱うためにTime
クラスが定義さています。
これらを扱いやすくするためにRailsのActiveSupportでタイムゾーンなどいくつか機能が拡張されているので、それらをまとめました。
時刻関連のテストはTimecopの使い方を参照してください。
動作確認
- Rails 4.1
- ActiveSupport 4.1.7
目次
- 本ページの動作の前提条件
- Rails4アプリ全体でタイムゾーンを設定
- ユーザー単位でタイムゾーンを設定
- タイムゾーン一覧とOSのタイムゾーンを確認
- 現在の日付(Date)を取得(Date.today, Date.current)
- 現在の時刻(Time)を取得する(Time.now)
- 指定した日時(Time)を作成する(Time.local)
- 昨日、明日を取得する(yesterday, tomorrow)
- 昨月、昨年、翌月、翌年を取得する(prev_xxx, next_xxx)
- 相対的な時刻(Time)を返す
- 開始時間と終了時間を取得する(beginning_of_xxx, end_of_xxx)
1. 本ページの動作の前提条件
- OS(Mac)のタイムゾーン: JST (+9:00) = Tokyo
- Railsのタイムゾーン : CST (-5:00/-6:00) = US & Canada(
application.rb
にconfig.time_zone = 'Central Time (US & Canada)'
を設定)
アメリカなどの場合、サマータイムがあるため日付に応じて自動的にタイムゾーンが変わります。
Time.zone.local(2014, 11, 1) #=> Sat, 01 Nov 2014 00:00:00 CDT -05:00 Time.zone.local(2014, 11, 29) #=> Sat, 29 Nov 2014 00:00:00 CST -06:00
2. Rails4アプリ全体でタイムゾーンを設定
Rails全体のタイムゾーンを設定するにはapplication.rb
のconfig.time_zone
にタイムゾーンを設定します。
# config/application.rb # デフォルトはUTC (0:00) # タイムゾーンをセントラルタイム(CDT -5:00 / CST -6:00)に設定 # config.time_zone = 'Central Time (US & Canada)' # タイムゾーンを東京(JST +9:00)に設定 # config.time_zone = 'Tokyo'
設定可能なタイムゾーンは「タイムゾーン一覧とOSのタイムゾーンを確認」を参照してください。
3. ユーザー単位でタイムゾーンを設定
ユーザー単位でタイムゾーンを設定するには、ユーザーにタイムゾーンを保持するカラムを追加し、コントローラーで設定する必要があります。rails g migration add_time_zone_to_users time_zone rake db:migrate
モデルにバリデーションをつける。
# app/models/user.rb valications :time_zone, inclusion: { in: ActiveSupport::TimeZone.zones_map(&:name) }
ビューで更新するようにする。
# app/views/users/_form.html.erb <div class="field"> <%= f.label :time_zone %><br /> <%= f.time_zone_select :time_zone %> </div>
StringParamterにtime_zone
を追加する。
# app/controllers/users_controller.rb private def users_params params.require(:user).permite(..., :time_zone) end
コントローラーでタイムゾーンを設定する。
# app/controllers/application_controller.rb around_action :user_time_zone, if: :current_user private def user_time_zone(&block) Time.use_zone(current_user.time_zone, &block) end end
4. タイムゾーン一覧とOSのタイムゾーンを確認
rake time:zones:all
ですべてのタイムゾーンを確認できます。
rake time:zones:all * UTC -11:00 * American Samoa International Date Line West Midway Island Samoa * UTC -10:00 * Hawaii * UTC -09:00 * Alaska ...
OSのタイムゾーンはrake time:zones:local
で確認できます。
rake time:zones:local * UTC +09:00 * Osaka Sapporo Seoul Tokyo Yakutsk
5. 現在の日付(Date)を取得(Date.today, Date.current)
Date.today
で、現在の日付を取得するDate.current
で、タイムゾーンに基づいた現在の日付を取得する
# JST (+ 9:00) Date.today # => Sat, 29 Nov 2014 # CST (- 5:00) Date.current #=> Sat, 29 Nov 2014 # Time.zoneかconfig.time_zoneがセットされている場合、Time.zone.todayの結果を返す # セットされていない場合、Date.todayの結果を返す
6. 現在の時刻(Time)を取得する(Time.now)
Time.now
で、現在の日時を取得するTime.zone.now
で、タイムゾーンに基づいた現在の日時を取得する
Time.now #=> 2014-11-29 17:00:46 +0900 Time.zone.now #=> Sat, 29 Nov 2014 02:01:41 CST -06:00 Time.current #=> Sat, 29 Nov 2014 02:01:41 CST -06:00 # Time.zonかconfig.time_zoneがセットされている場合、Time.zone.nowの結果を返す # セットされていない場合、Tiem.nowの結果を返す
7. 指定した日時(Time)を作成する(Time.local)
Time.local
で、指定した日時を取得するTime.zone.local
で、タイムゾーンに基づいた指定した日時を取得する
Time.local(2014, 11, 29, 11, 22, 33) #=> 2014-11-29 11:22:33 +0900 Time.zone.local(2014, 11, 29, 11, 22, 33) #=> Sat, 29 Nov 2014 11:22:33 CST -06:00
8. 昨日、明日を取得する(yesterday, tomorrow)
Time#yesterday
で、前日の日時を取得するTime#tomorrow
で、翌日の日時を取得する
t = Time.local(2014, 11, 30) #=> 2014-11-30 00:00:00 +0900 t.yesterday #=> 2014-11-29 00:00:00 +0900 t.tomorrow #=> 2014-12-01 00:00:00 +0900 # タイムゾーンは呼び出し元のTimeオブジェクトに依存する t2 = Time.zone.local(2014, 11, 29) #=> Sat, 29 Nov 2014 00:00:00 CST -06:00 t2.yesterday #=> Fri, 28 Nov 2014 00:00:00 CST -06:00 t2.tomorrow #=> Sun, 30 Nov 2014 00:00:00 CST -06:00
9. 昨月、昨年、翌月、翌年を取得する(prev_xxx, next_xxx)
次のメソッドが定義されています。- Time#prev_month, Date#prev_month
- Time#next_month, Date#next_month
- Time#prev_year, Date#prev_year
- Time#next_year, Date#next_year
また、タイムゾーンは呼び出し元のオブジェクトに依存します。
10. 相対的な時刻(Time)を返す
ActiveSupportによりNumericクラスには次のメソッドが拡張されている。- years (年)
- mounths (月)
- weeks (週)
- days (日)
- hours (時間)
- minutes (分)
- seconds (秒)
そして、次のメソッドをメソッドチェインすることで相対的な日付を返す
- 後: from_now or since
- 前: until or ago(time = :Time.current)
デフォルトで引数にTime.current
が指定されているため、Railsのタイムゾーンに基づいた現在日時からの相対時間を返す
Time.current # => Sat, 29 Nov 2014 02:20:08 CST -06:00 # 1週間前 1.weeks.ago # => Sat, 22 Nov 2014 02:21:23 CST -06:00 # 1日後 1.days.from_now # => Sun, 30 Nov 2014 02:20:32 CST -06:00 # 引数を指定することで、その日からの相対的な時間を指定できる t = Time.local(2014, 11, 1) #=> 2014-11-01 00:00:00 +0900 1.months.ago(t) #=> 2014-10-01 00:00:00 +0900
11. 開始時間と終了時間を取得する(beginning_of_xxx, end_of_xxx)
DateクラスとTimeクラスには、開始時刻や終了時刻を取得するために次のメソッドが定義されています。- beginning_of_hour, end_of_hour
- beginning_of_day, end_of_day
- beginning_of_week, end_of_week
- beginning_of_month, end_of_month
- beginning_of_quarter, end_of_quarter
- beginning_of_year, end_of_year
次のようにすることで、ActiveRecordで月単位などでレコードを取得ができる
now = Time.current #=> Sat, 29 Nov 2014 02:26:53 CST -06:00 Order.where(order_at: now.beginning_of_month..now.end_of_month)
以上です。
参考文献
- Ruby on Rails API
- Rails3 レシピブック 190の技
- #106 Time Zones (revised) - RailsCasts