Rで時刻の差をとるときは単位を指定する癖をつける(もしくはlubridate::time_length()を用いる)

時刻を入れたデータフレームがあるとする。

> smp <- data.frame(now=Sys.time(), then=Sys.time()-60) 
> smp 
   now                               then 
1 2019-02-09 10:30:15 2019-02-09 10:29:15 

で、時刻の差を計算すると、そこに単位も含まれてくる。

> smp$diff <- with(smp, now - then) 
> smp now then diff 
1 2019-02-09 10:30:15 2019-02-09 10:29:15 59.99999 secs 

これは煩わしいので、as.numeric()で数値に変える。

> smp$diff <- with(smp, as.numeric(now - then)) 
> smp 
    now                              then                              diff
 1 2019-02-09 10:30:15 2019-02-09 10:29:15 59.99999 

一見問題ないように見えるが、次のような時に困る。

> smp <- data.frame(now=Sys.time(), then=Sys.time()-3600) 
> smp$diff <- with(smp, as.numeric(now - then)) 
> smp 
   now                              then                                diff 
1 2019-02-09 10:38:55 2019-02-09 09:38:55 60 

これは時刻の差分を計算する時に呼び出されるdifftime()の引数unitsがデフォルトではautoとなっていることに起因する。 したがっていつも同じ単位で結果が欲しいときは、演算子ではなくdifftime()を用いて、unitsを指定するとよい。

> smp$diff <- with(smp, as.numeric(difftime(now, then, units = "secs"))) 
> smp                              
   now                              then                                diff 
1 2019-02-09 10:45:00 2019-02-09 09:45:00 3600 

もしくはlubridateパッケージでtime_length()を用いるという手もある。 こちらはデフォルトがsecsになっている。 なお、time_length()はIntervalクラスの値を求めるので、interval()してから渡してやる必要がある点に注意。

> smp$diff <- with(smp, time_length(interval(then, now))) 
> smp                              
   now                              then                                diff 
1 2019-02-09 10:45:00 2019-02-09 09:45:00 3600 

interval()の演算子として%--%も用意されているので、パイプを使いたいときはこちらもあり。

> smp <- smp %>% + mutate(diff = then %--% now %>% time_length()) 
> smp 
now then diff 
1 2019-02-09 10:49:53 2019-02-09 09:49:53 3600 

いかがでしたか????