「2012-07-04 10:01:08」のような日時を5分など任意のスパンで丸める

csvなどのデータを読み込んで "2017-09-01 13:15:23" のような時間の表記を含んでいるものをさあ集計しようとすると、秒まで入っているので、

- 時間単位でまとめて集計したい　とか
- 月単位でまとめたい集計したい　とか

の時に困ったりします。

「何かちゃんとしたやりかたあるんだろうなあ」と思いつつ文字列にして半ば強引に文字列操作でやってました。

```R
# サンプルデータ
test <- as.POSIXct(c(
    "2017-09-01 14:31:21",
    "2017-09-01 15:40:43",
    "2017-09-01 16:20:26",
    "2017-09-01 17:22:16",
    "2017-09-01 18:30:37"
))
```

# 文字列で半ば力技

```R
> # 時間で丸める
> paste(substr(test,1,14),"00",sep="")
"2017-09-01 15:00" "2017-09-01 15:00" "2017-09-01 16:00" "2017-09-01 16:00" "2017-09-01 16:00"

> # 月単位で丸める
> paste(substr(test,1,8),"01",sep="")
"2017-09-01" "2017-09-01" "2017-09-01" "2017-09-01" "2017-09-01"
```
これで集計はできなくはないけど、POSIXctせずに文字列のままいけるけど、
なんだかなあと思う日々。

それに5分とか15分とかでまとめたい時に逆に面倒になる。

# 丸めるならroundじゃない？
と思って調べてみると、できそう。

```R
> # 分で丸める
> round(test,"mins")
[1] "2017-09-01 15:31:00 JST" "2017-09-01 15:41:00 JST" "2017-09-01 16:20:00 JST" "2017-09-01 16:22:00 JST" "2017-09-01 16:31:00 JST"

> # 時間で丸める
> round(test,"hours")
[1] "2017-09-01 16:00:00 JST" "2017-09-01 16:00:00 JST" "2017-09-01 16:00:00 JST" "2017-09-01 16:00:00 JST" "2017-09-01 17:00:00 JST"

> # 日で丸める
> round(test,"days")
[1] "2017-09-02 JST" "2017-09-02 JST" "2017-09-02 JST" "2017-09-02 JST" "2017-09-02 JST"
```
おお、いい感じ。
でも調子に乗ると、、

```R
> # 月で丸めたい！
> round(test,"month")
 match.arg(units) でエラー: 
   'arg' は “secs”, “mins”, “hours”, “days” の一つでなければなりません： 

> # 15分で丸めたい！
> round(test,"15 mins")
 match.arg(units) でエラー: 
   'arg' は “secs”, “mins”, “hours”, “days” の一つでなければなりません： 
```
oh.. 使えるのは 秒、分、時間、日 の単位のみ。
あと一息、帯に短い。。

# まさかcutが使えるとは。
数字のベクトルをよしなに切り分けてくれるcut。
この子が時間でも切り分けてくれるらしい。灯台下暗し。

```R
> # 15分で丸める
> cut(test,"15 mins")
[1] 2017-09-01 14:31:00 2017-09-01 15:31:00 2017-09-01 16:16:00 2017-09-01 17:16:00 2017-09-01 18:16:00
16 Levels: 2017-09-01 14:31:00 2017-09-01 14:46:00 2017-09-01 15:01:00 2017-09-01 15:16:00 2017-09-01 15:31:00 ... 2017-09-01 18:16:00

> # 2時間で丸める
> cut(test,"2 hours")
[1] 2017-09-01 14:00:00 2017-09-01 14:00:00 2017-09-01 16:00:00 2017-09-01 16:00:00 2017-09-01 18:00:00
Levels: 2017-09-01 14:00:00 2017-09-01 16:00:00 2017-09-01 18:00:00

> # 月で丸める
> cut(test,"month")
[1] 2017-09-01 2017-09-01 2017-09-01 2017-09-01 2017-09-01
Levels: 2017-09-01

> # 年だってOK
> cut(test,"years")
[1] 2017-01-01 2017-01-01 2017-01-01 2017-01-01 2017-01-01
Levels: 2017-01-01
```
これはちょっとうれしい。
※ただしfactor形式になるので注意。

#（追記）パッケージlubridateを使う。
コメントを頂いて、tidyverseの中のlubridateでもできるとのこと。
lubridateは ymd()だとか mdy()だとかくらいしか認知していなかったけど、こんなのもあるのね。

```R
> library(lubridate)

> # 15分で丸める
> round_date(test,"15 mins")
[1] "2017-09-01 14:30:00 JST" "2017-09-01 15:45:00 JST" "2017-09-01 16:15:00 JST" "2017-09-01 17:15:00 JST" "2017-09-01 18:30:00 JST"


> # 2時間で丸める
> round_date(test,"2 hours")
[1] "2017-09-01 14:00:00 JST" "2017-09-01 16:00:00 JST" "2017-09-01 16:00:00 JST" "2017-09-01 18:00:00 JST" "2017-09-01 18:00:00 JST"

> # 月で丸める
> round_date(test,"month")
[1] "2017-09-01 JST" "2017-09-01 JST" "2017-09-01 JST" "2017-09-01 JST" "2017-09-01 JST"

> # 年だってOK
> round_date(test,"years")
[1] "2018-01-01 JST" "2018-01-01 JST" "2018-01-01 JST" "2018-01-01 JST" "2018-01-01 JST"
```
しかも返り値がPOSIXctのままで便利。
マニュアル見ると、
"week", "bimonth", "quarter"=="3 months", "halfyear" などでもOKらしい。

また、加えて、丸めるだけでなく、切り捨てや切り上げも出来て便利。

```R
> test
[1] "2017-09-01 14:31:21 JST" "2017-09-01 15:40:43 JST" "2017-09-01 16:20:26 JST" "2017-09-01 17:22:16 JST"
[5] "2017-09-01 18:30:37 JST"

> # そのまま丸める
> round_date(test,unit="5 mins")
[1] "2017-09-01 14:30:00 JST" "2017-09-01 15:40:00 JST" "2017-09-01 16:20:00 JST" "2017-09-01 17:20:00 JST"
[5] "2017-09-01 18:30:00 JST"

> # 切り捨て（それより小さい最大）
> floor_date(test,unit="5 mins")
[1] "2017-09-01 14:30:00 JST" "2017-09-01 15:40:00 JST" "2017-09-01 16:20:00 JST" "2017-09-01 17:20:00 JST"
[5] "2017-09-01 18:30:00 JST"

> # 切り下げ（それより大きい最少）
> ceiling_date(test,unit="5 mins")
[1] "2017-09-01 14:35:00 JST" "2017-09-01 15:45:00 JST" "2017-09-01 16:25:00 JST" "2017-09-01 17:25:00 JST"
[5] "2017-09-01 18:35:00 JST"
> 
```


enjoy!