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

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

それぞれの日付型の意味についてはこちらの記事を参照してみてください。
[RubyとRailsにおけるTime, Date, DateTime, TimeWithZoneの違い](http://qiita.com/jnchito/items/cae89ee43c30f5d6fa2c)

## x日前

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

```rb
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でいけるよ

```rb
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

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

```rb

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`を作成

```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)
```

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

```rb
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`を作成

```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**

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

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

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

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

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

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

```rb
date = Date._strptime('2017年9月1日','%Y年%m月%d日')
p date
# {:year=>2017, :mon=>9, :mday=>1}
```

## 日付の差分

Date型は、ただ引くだけ

```rb
d = Date.new(2017,9,7)
d2 = Date.new(2017,10,11)

p d2-d
# (34/1)

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

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

```rb
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をいれてあげよう。

```rb
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_month`、`end_of_month`

```rb
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で出してくれるので助かるー

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

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

## 今週（来週）のhoge曜日の日付を出す

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

```rb
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）

```rb
t = Time.current
t.prev_week(:friday) # 先週の金曜日
t.next_week(:friday) # 来週の金曜日

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