round a date in R to an arbitrary minute/hour level of precision

和自甴很熟 提交于 2021-02-04 17:08:19

问题


I'm looking to group dates in R by an arbitrary level of precision.

It's pretty straightforward to do this to the nearest hour or minute, using e.g. lubridate:

library(lubridate)
nearest_hour = floor_date(now(), 'hour')

You can then group a list of such dates with e.g. a simple summarise ddply from plyr.

What I'd like to do is round dates with arbitrary precision, e.g. to the nearest 15 minutes or every 3 hours:

nearest_three_hours = floor_date(now(), '3 hours')

There's a discussion of such things at http://r.789695.n4.nabble.com/Truncating-dates-and-other-date-time-manipulations-td866901.html but outside of cutting dates, there doesn't appear to have been any resolution.


回答1:


lubridate already floors to the nearest atomic unit. To get floor to the nearest 15 minutes, which I think is what you want to do (not round), you just need to map into the correct range via findInterval and a defined set of breakpoints. Try this floor_time, which is functionally equivalent to floor_date, but allows you to specify a variable # of units for seconds, minutes or hours.

floor_time <- function(x, k = 1, unit = c("second", "minute", "hour", "day", 
                                          "week", "month", "year")) {
  require(lubridate)

  nmax <- NULL

  switch(unit, second = {nmax <- 60},
         minute = {nmax <- 60},
         hour = {nmax <- 24})

  cuts <- seq(from = 0, to = nmax - 1, by = k)
  new <- switch(unit, 
                second = update(x, seconds = cuts[findInterval(second(x), cuts)]), 
                minute = update(x, minutes = cuts[findInterval(minute(x), cuts)], 
                                seconds = 0), 
                hour = update(x, hours = cuts[findInterval(hour(x), cuts)], 
                              minutes = 0, seconds = 0), 
                day = update(x, hours = 0, minutes = 0, seconds = 0), 
                week = update(x, wdays = 1, hours = 0, minutes = 0, seconds = 0), 
                month = update(x, mdays = 1, hours = 0, minutes = 0, seconds = 0), 
                year = update(x, ydays = 1, hours = 0, minutes = 0, seconds = 0))

  new
}



回答2:


A little late, and I don't have rep to comment, but as Selva mentioned, lubridate now has this functionality:

library(lubridate)
round_date(now(), '3 hours')
floor_date(now(), '3 hours')
ceiling_date(now(), '3 hours')



回答3:


You can try this, still based on the lubridate library

library(lubridate)
round_minute<-function(x,precision){
  m<-minute(x)+second(x)/60
  m.r<- round(m/precision)*precision
  minute(x)<-m.r
  second(x)<-0
  x
}

round_minute(ymd_hms(c("2013-06-03 22:53:00","2013-05-03 12:18:00","2013-05-03 00:10:00")),15)

> "2013-06-03 23:00:00 UTC" "2013-05-03 12:15:00 UTC" "2013-05-03 00:15:00 UTC"

The code handle well all the tricky situations thanks to lubridate. Of course this function works only for precision expressed in minutes but you can easily extend it to other units, and even create a generic function if you really need it.




回答4:


lubridate now has a more generic round_date() function.

lubridate::round_date(date, "5 mins")
lubridate::round_date(date, "2 hours")


来源:https://stackoverflow.com/questions/16803867/round-a-date-in-r-to-an-arbitrary-minute-hour-level-of-precision

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!