Railsのアプリで特定の期間の料金計算をしたり、そのテストをする際に時間をいじって検証することが多かったのですが、かなり簡単に欲しい時刻を取得できることに感動したので、そのとき使った時間操作系のメソッドを備忘録代わりにまとめました。
そもそもTimeとかTimeWithZoneとか何なのか?
下記の記事に詳しく書かれていたので紹介させていただきます。結論、Railsで使うときはTimeWithZoneを使うと色々捗ります。この記事ではこのクラスを使うことを前提に書かせていただきます。
RubyとRailsにおけるTime, Date, DateTime, TimeWithZoneの違い - Qiita
現在時刻の取得する
超基本の時刻取得系。とりあえず基本ということで。これをベースにいろんな形に変換したりしていくことが多いかと思います。
# 現在時刻を取得する
Time.current
=> Wed, 15 Jan 2020 13:18:07 UTC +00:00
# classを確認する
Time.current.class
=> ActiveSupport::TimeWithZone
# string型に変換
Time.current.strftime("%F")
=> "2020-01-15"
Tips: Time.nowとの違い
Time.now
を使っても現在時刻は取得できますが、こちらの場合は下記のような違いがあります。
- Timeクラスなので、TimeWithZoneのメソッド(今回紹介しているものなど)が使えない。
- TimeWithZoneは
config/application.rb
に設定しているタイムゾーンをもとに取得してくるのに対して、環境変数、もしくはシステムのタイムゾーンをもとに現在時刻を取得するため、時刻が大きくずれてしまうという懸念がある。
TimeWizhZoneクラスのメソッドが使えることからも、こちらで取得するのが良さそうです。
前日や翌日を取得する
昨日のデータ、翌月のデータを取得したい〜と思うのですがこのレベルであれば下記のように一発で持ってこれるので便利です。
# 昨日
Time.current.yesterday
# 翌日
Time.current.tomorrow
# 前月
Time.current.prev_month
# 翌月
Time.current.next_month
# 月初
Time.current.beginning_of_month
# 月末
Time.current.end_of_month
# 前年
Time.current.prev_year
# 翌年
Time.current.next_year
N日、Nヶ月、N年前の時刻を取得する
任意の日付や月で変更したい場合は下記のように書くことで取得することが可能です。
# 3日前 / 3日後
Time.current.ago(3.days)
Time.current.since(3.days)
# 3ヶ月前 / 3ヶ月後
Time.current.ago(3.month)
Time.current.since(3.month)
# 3年前 / 3年後
Time.current.ago(3.years)
Time.current.since(3.years)
年月日や曜日を取得する
日数の計算などする際は下記のように書くことでそれぞれの数字が持ってこられます。この時の型は基本int型です。
# 年
Time.current.year
=> 2020
# 月
Time.current.month
=> 6
# 日付
Time.current.day
=> 7
時刻の差分
TimeWithZoneを引算すると、UNIXTIME(秒数)が返ってきます。これをTime.zone.atを使って変換することで、2つの日時の差分から日付などを取得したいときに使えます。
# 時刻を設定からTimeWithZoneに変換する
time1 = Time.zone.parse('2020-01-05 12:00:00')
time2 = Time.zone.parse('2020-01-01 10:00:00')
# 引算してUNIXTIME(秒数) を取得する
time1 - time2
=> 352800.0
# 秒数をTimeWithZoneに変換する
Time.zone.at(time1 - time2)
任意の時間を取得する
テストなどで特定の日付に生成したデータなどを取得したい場合などに使います。
Time.zone.parse('2020-01-01')
=> Wed, 01 Jan 2020 00:00:00 UTC +00:00
Time.zone.parse('2020-01-01 12:00:00')
=> Wed, 01 Jan 2020 12:00:00 UTC +00:00
# 現在時刻をもとに新しいTimeWithZoneを作成する
Time.zone.parse("#{Time.current.strftime('%F')} #{Time.current.hour}:00:00")
=> Wed, 15 Jan 2020 13:00:00 UTC +00:00
まとめ
時刻操作などは触る前は少し苦手意識がありましたが、こうして触ってみて学びも増えました。他にもできることが便利な操作法があれば追加していこうと思います。