Posted at

すぐ忘れるので、RubyとRailsの日付操作周りについてまとめました

More than 1 year has passed since last update.

日付の操作はしょっちゅうするのですが、なんか毎回調べているにも関わらず、いっこうに頭に入ってこないのでまとめました。

それぞれの日付型の意味についてはこちらの記事を参照してみてください。

RubyとRailsにおけるTime, Date, DateTime, TimeWithZoneの違い


x日前


ruby

Date型なら -1 するだけです

require "date"

d = Date.today
p d
p d-1

#<Date: 2017-09-07 ((2458004j,0s,0n),+0s,2299161j)>
#<Date: 2017-09-06 ((2458003j,0s,0n),+0s,2299161j)>

DateTimeも -1でいけるよ

require "date"

d = DateTime.now
p d
p d-1

#<DateTime: 2017-09-15T17:52:04+09:00 ((2458012j,31924s,725447000n),+32400s,2299161j)>
#<DateTime: 2017-09-14T17:52:04+09:00 ((2458011j,31924s,725447000n),+32400s,2299161j)>

Timeは1秒マイナスするだけや

now = Time.now

p now
p now -1

# 2017-09-07 17:52:54 +0900
# 2017-09-07 17:52:53 +0900


rails(ActiveSupport)

-1.days

[2] pry(main)> Time.current

=> Fri, 18 Aug 2017 18:12:21 JST +09:00
[3] pry(main)> Time.current - 1.days
=> Thu, 17 Aug 2017 18:12:26 JST +09:00


x月前


ruby

<<演算子で前の月の日付オブジェクトを返します


require "date"
d = Date.new(2017,9,7)
p d
p d << 2
# d.prev_month(2)でも同じ

#<Date: 2017-09-07 ((2458004j,0s,0n),+0s,2299161j)>
#<Date: 2017-07-07 ((2457973j,0s,0n),+0s,2299161j)>


rails(ActiveSupport)

Time.current-2.month

[1] pry(main)> Time.current

=> Fri, 15 Sep 2017 18:22:33 JST +09:00
[2] pry(main)> Time.current-2.month
=> Tue, 15 Aug 2017 18:22:42 JST +09:00


x時間、x分、x秒後

俺は15分後が何時何分何秒か知りたいのだ、そんな時に。

require "date"

d = DateTime.new(2017,4,1,0,0,0)

p d + Rational(1,24)
p d + Rational(1,24*60)
p d + Rational(1,24*60*60)

#<DateTime: 2017-04-01T01:00:00+00:00 ((2457845j,3600s,0n),+0s,2299161j)>
#<DateTime: 2017-04-01T00:01:00+00:00 ((2457845j,60s,0n),+0s,2299161j)>
#<DateTime: 2017-04-01T00:00:01+00:00 ((2457845j,1s,0n),+0s,2299161j)>



フォーマットの変更(日付型→文字列型)

よく使うやつ

strftime

Date.new(2017,9,7).strftime("%Y-%m-%d")

Time.new(2017,9,1).strftime("%Y-%m-%d")


rails

config/initializers/time_formats.rbを作成

Time::DATE_FORMATS[:ja] = "%Y年%m月%d日 %H時%M分"

Time::DATE_FORMATS[:ymd] = "%Y%m%d"

みたいな感じで好きにフォーマットつくれます。

使い方

Time.new(2017,9,1).to_s(:ja)

デフォルトで用意されているフォーマット

Time.new(2017,9,1).to_s(:default)=> "2017-09-01 00:00:00 +0900"

Time.new(2017,9,1).to_s(:long)=> "September 01, 2017 00:00"
Time.new(2017,9,1).to_s(:short)=> "01 Sep 00:00"
Time.new(2017,9,1).to_s(:db)=> "2017-09-01 00:00:00"

※defaultフォーマットを上書きすることで、デフォルトを変えることも可能

ja.ymlを使う

config/initializers/locale.rbを作成

I18n.default_locale = :ja

config/locales/ja.ymlを作成

https://github.com/svenfuchs/rails-i18n/blob/master/rails/locale/ja.yml

を流用させていただきます

irb(main):001:0> I18n.l(Time.current, format: :long)

=> "2017年09月20日(水) 19時46分15秒 +0900"


文字列を日付型に変換

strptime

date = Date.strptime('2017年9月1日','%Y年%m月%d日')

p date

#<Date: 2017-09-01 ((2457998j,0s,0n),+0s,2299161j)>

ハイフン区切り、スラッシュ区切りの日付なら、parseでいけます。

date = Date.parse('2017-9-7')

p date

#<Date: 2017-09-01 ((2457998j,0s,0n),+0s,2299161j)>


_strptimeとか_parse

Dateクラスには通常のメソッドにアンダースコア(_)が先頭についたメソッドがいくつかありまして、要素をハッシュで返してくれるようになります。

date = Date._strptime('2017年9月1日','%Y年%m月%d日')

p date
# {:year=>2017, :mon=>9, :mday=>1}


日付の差分

Date型は、ただ引くだけ

d = Date.new(2017,9,7)

d2 = Date.new(2017,10,11)

p d2-d
# (34/1)

# Rational型で返るので分子の値だけを取れば日付の差分が取得できます
p (d2-d).numerator
# 34

Timeでやると、秒数で出ちゃうので割ります

t  = Time.new(2017,9,7)

t2 = Time.new(2017,10,11)
p t2-t
p (t2-t)/24/60/60
# 2937600.0
# 34


月末、月初


ruby

月末はDateオブジェクトを作る時に日付の値に-1をいれてあげよう。

require "date"

d = Date.new(2017,9,-1)
p d
#<Date: 2017-09-30 ((2458027j,0s,0n),+0s,2299161j)>

dt = DateTime.new(2017,9,-1)
p dt
#<DateTime: 2017-09-30T00:00:00+00:00 ((2458027j,0s,0n),+0s,2299161j)>

t = Time.new(2017,9,-1)
p t
# /tmp/sample.rb:6:in `initialize': argument out of range (ArgumentError)
# Timeはエラー


rails(ActiveSupport)

rails使う場合は月末、月初を出すメソッドあります。

beginning_of_monthend_of_month

t = Time.new(2017,9.7)

# => 2017-09-01 00:00:00 +0900
t.beginning_of_month
# => 2017-09-01 00:00:00 +0900
t.end_of_month
# => 2017-09-30 23:59:59 +0900

23:59:59で出してくれるので助かるー


指定した日付の曜日を出す

require "date"

d = Date.new(2017,9,7)
p %w(日 月 火 水 木 金 土)[d.wday]


今週(来週)のhoge曜日の日付を出す

https://qiita.com/14021939/items/b6c13367042b8192936d

require "date"

this_day = Date.today
this_monday = this_day - (this_day.wday - 1) # 今週
this_tuesday = this_day - (this_day.wday - 2) # 今週
this_wednesday = this_day - (this_day.wday - 3) # 今週
next_wednesday = this_day - (this_day.wday - 3) + 7 # 来週


rails(activesupport)

t = Time.current

t.prev_week(:friday) # 先週の金曜日
t.next_week(:friday) # 来週の金曜日

t + (5 - t.wday).days # 今週の金曜日
t + (4 - t.wday).days # 今週の木曜日