rdatetimedplyrlubridatezoo

R Lubridate: Round/Snap datetime to the nearest arbitrary time of day?


I have a list of datetimes like the following:

data <- data.frame(datetimes = c(ymd_hms("2024-01-01 04:12:35"), 
                                 ymd_hms("2024-04-01 14:52:20"), 
                                 ymd_hms("2024-03-18 23:43:56")))

I would like to round/snap each of these date times to the next occurrence of a specified time of day.

For example, if I choose a time of 10:30:00 I would like to round up each of these dates so that:

2024-01-01 04:12:35 becomes -> 2024-01-01 10:30:00.

2024-04-01 14:52:20 becomes -> 2024-04-02 10:30:00.

2024-03-18 23:43:56 becomes -> 2024-03-19 10:30:00.

Is there a way to easily do this?

Thanks


Solution

  • 1) Add 1 to the date if the datetime is past 10:30:00 and paste 10:30:00 and convert back to POSIXct.

    library(dplyr)
    library(lubridate)
    
    cutoff <- "10:30:00" # specify as string
    data %>%
      mutate(datetimes2 = 
        (as.Date(datetimes) + (sub(".* ", "", datetimes) > cutoff)) %>%
        paste(cutoff) %>% 
        ymd_hms)
    
    ##             datetimes          datetimes2
    ## 1 2024-01-01 04:12:35 2024-01-01 10:30:00
    ## 2 2024-04-01 14:52:20 2024-04-02 10:30:00
    ## 3 2024-03-18 23:43:56 2024-03-19 10:30:00
    

    2) Alternately subtract 10.5*3600, extract the date, add 1, convert back to POSIXct and add the seconds back on.

    cutoff <- 10.5 * 3600 # specify in seconds
    data %>%
      mutate(datatimes2 = as.POSIXct(as.Date(datetimes-cutoff)+1) + cutoff)
    
    ##             datetimes          datatimes2
    ## 1 2024-01-01 04:12:35 2024-01-01 10:30:00
    ## 2 2024-04-01 14:52:20 2024-04-02 10:30:00
    ## 3 2024-03-18 23:43:56 2024-03-19 10:30:00