Does R not know that time is circular? How to find closest time of the day to a given time

 ̄綄美尐妖づ 提交于 2021-01-24 07:44:51

问题


23:59:59 o'clock is closer to midnight than 03:00:00 o'clock to midnight, for example. Unfortunately, R tells the opposite (at least the package I use). Here is what I mean:

In fact I do not only care about midnight but I need to find the closest time of the day in a vector to a given time and I do not care about the date. There is a similiar question with a great answer but the code doesn't work as expected because in the link time is a timeline not a circle. See here:

library("chron")
x <- times(c("00:00:02", "23:59:59"))
v <- times("00:00:00")
indx <- which(abs(x-v) == min(abs(x - v)))
x[indx]
00:00:02 # which is further from 00:00:00 than 23:59:59

According to the code all times between 00:00:00 and 23:59:59 are closer to midnigth than 23:59:59. For example, this leads to the confusing result that 16:23:11 is closer to midnight than 23:59:59. So R seems to start at 00:00:00 and end at 23:59:59 and thus "does not see" that 23:59:59 is pretty close to 00:00:00. I understand that this makes sense if we take into account dates: For example, 2001-01-01 00:00:02 is closer to 2001-01-01 00:00:00 than is 2001-01-01 23:59:59 to 2001-01-01 00:00:00. But how to find the closest time of the day where one considers the time as a circle?


回答1:


Edit for a more general solution:

If you are just looking for a nice general solution for this problem:

Since this solution above is only applicable for a very specific situation I tried to create a more general solution. I created a function that wil find to time in a vector closest to a given time.

library('chron')

#' This function returns the time in 'timeVector' that is 
#' closest to 'time'
closest.time <- function(timeVector, time) {
  times()
  x <- times(timeVector)
  v <- times(time)

  clockwise_distance = abs(x - v) 
  anticlockwise_distance = times("23:59:59") - clockwise_distance + times("00:00:01")
  clockwise_and_anticlockwise <-  matrix(c(anticlockwise_distance,  clockwise_distance), ncol = 2)
  shortest_distance_of_the_two <- apply(clockwise_and_anticlockwise, 1, min)

  indx <- which(shortest_distance_of_the_two == min(shortest_distance_of_the_two))

  x[indx]
}

This solution is based on the idea that there are two ways to go round the circle. The first is just the normal clockwise distance. The second is the anticlockwise distance. Since the whole circle is 24 hours, the anticlockwise distance is '24_hours - clockwise_distance'.

Then for each value in timesVector there should be checked if the clockwise or anticlockwise distance is the shortest.

Lastly, there should be checked which time in timeVector is closest to time

Old answer

Since chron does not have a nice function to do this and I can't come up with a solution that uses the times data type, I am going to abandon times and use POSIXct instead.

POSIXct also has a date attribute that you said you don't want to use. This is why the date in our POSIXct is just a dummy value that we don't really look at, except for changing it in ways to solve our problem.

x <- c("00:00:02", "23:59:59")
x <- as.POSIXct(x, format = "%H:%M:%OS")
v <- as.POSIXct("00:00:00", format = "%H:%M:%OS")

# I subtract 24 hours to center all times around the same midnight.
mid.day <- as.POSIXct("12:00:00", format = "%H:%M:%OS")
x[x > mid.day] <- x[x > mid.day] - 24*60*60

# I used your same approach to check the time closest to midnight.
# you might want to change this to something that uses difftime(). Ask me if you  need help with this.
indx <- which(abs(x-v) == min(abs(x - v)))

# shows us the POSIXct object the way we want to see it (only time)
format(x[indx], format="%H:%M:%S")

Note that you might want to use difftime(x,y) now to get the difference in time

 indx <- which(abs(difftime(x, v)) == min(abs(difftime(x, v))))


来源:https://stackoverflow.com/questions/56324087/does-r-not-know-that-time-is-circular-how-to-find-closest-time-of-the-day-to-a

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