Search code examples
rdata.tabledata-conversionduration

Is there any way of preserving the hundredths of seconds with the function "as.ITime" of data.table?


I'd like to transform a column of a table of class "data.table" which is in characters ("01:22:03.56" for example) into date format with the [data.table] function "as.ITime", but I lose the hundredths of seconds after conversion (01:22:03). Is there any way of preserving the hundredths of seconds with [data.table]?


Solution

  • Up front: ITime by-design stores as an integer. From ?as.ITime:

    Description:
    
         Date and time classes with integer storage for fast sorting and
         grouping. Still experimental!
    

    This means there is no direct way of storing the time with milliseconds using as.ITime.

    Options, which is best depends heavily on what your follow-on processing requires.

    1. Use lubridate::hms, which creates an object of class "Period".

      tm <- lubridate::hms("01:22:03.56")
      tm + 5
      # [1] "1H 22M 8.56S"
      ### this will look odd ...
      tm - 5
      # [1] "1H 22M -1.44S"
      ### ... but it works out in the end
      (tm + 5) - (tm - 5)
      # [1] "10S"
      
    2. Pick a date (arbitrary) and prepend it to the time, then use as.POSIXct:

      tm <- as.POSIXct(paste("1970-01-01", "01:22:03.56"))
      tm
      # [1] "1970-01-01 01:22:03 EST"
      ### to prove that milliseconds are in there, you can either
      dput(tm)
      # structure(22923.56, class = c("POSIXct", "POSIXt"), tzone = "")
      ### or you can set how it is rendered on the console
      options(digits.secs=3)
      tm
      # [1] "1970-01-01 01:22:03.56 EST"
      tm + 5
      # [1] "1970-01-01 01:22:08.56 EST"
      tm - 5
      # [1] "1970-01-01 01:21:58.56 EST"
      
    3. If all you need is a numeric interpretation of that time, then

      time2num <- function(x) {
        vapply(strsplit(x, ':'), function(y) sum(as.numeric(y) * c(60*60, 60, 1)),
               numeric(1), USE.NAMES=FALSE)
      }
      tm <- time2num("01:22:03.56")
      tm
      # [1] 4923.56