Search code examples
rdataframestrptime

Handling integer times in R


Times in my data frame are recorded as integers as in: 1005,1405,745,1130,2030 etc. How do I convert these integers so R will understand and use it in functions such as strptime. Thanks in advance for your help


Solution

  • Solution using strptime()

    As was pointed out by Psidom in his comment, you can convert the integers to character and use strptime():

    int_times <- c(1005,1405,745,1130,2030)
    strptime(as.character(int_times), format="%H%M")
    ## [1] "2016-04-21 10:05:00 CEST" "2016-04-21 14:05:00 CEST" NA                        
    ## [4] "2016-04-21 11:30:00 CEST" "2016-04-21 20:30:00 CEST"
    

    However, as you can see, you run into trouble as soon as the number has only three digits. You can get around this by using formatC() to format the integers to character with four digits and a leading zero (if needed):

    char_times <- formatC(int_times, flag = 0, width = 4)
    char_times
    [1] "1005" "1405" "0745" "1130" "2030"
    

    Now, conversion works:

    strptime(char_times, format="%H%M")
    ## [1] "2016-04-21 10:05:00 CEST" "2016-04-21 14:05:00 CEST" "2016-04-21 07:45:00 CEST"
    ## [4] "2016-04-21 11:30:00 CEST" "2016-04-21 20:30:00 CEST"
    

    Note that strptime() always returns a POSIXct object that involves time and date. Since no data was given, the current day was used. But you could also use paste() to combine the times with any date:

    strptime(paste("2010-03-21", char_times), format="%Y-%m-%d %H%M")
    ## [1] "2010-03-21 10:05:00 CET" "2010-03-21 14:05:00 CET" "2010-03-21 07:45:00 CET"
    ## [4] "2010-03-21 11:30:00 CET" "2010-03-21 20:30:00 CET"
    

    Solution using lubridate::hm()

    As was suggested by Richard Telford in his comment, you could also make use of lubridate's period class, if you prefer not to have any date involved. This class is for periods of times and thus you could represent a clock time, say 10:23, as the period 10 hours, 23 minutes. However, simply using hm() from lubridate does not work:

    library(lubridate)
    hm(char_times)
    ## [1] NA NA NA NA NA
    ## Warning message:
    ## In .parse_hms(..., order = "HM", quiet = quiet) :
    ##   Some strings failed to parse
    

    The reason is that without a separator, it is not clear how these times should be converted. hm() just expects a representation that has hours before minutes. But "1005" could be 100 hours and 5 minutes just as well as 1 hour and 5 minutes. So you need to introduce a separation between hours and minutes, which you could do for instance as follows:

    char_times2 <- paste(substr(char_times, 1, 2), substr(char_times, 3, 4))
    hm(char_times2)
    ## [1] "10H 5M 0S"  "14H 5M 0S"  "7H 45M 0S"  "11H 30M 0S" "20H 30M 0S"
    

    Note that I have again used the fixed width string represantation char_times, because then the hours are always given by the first two characters. This makes it easy to use substr().