Search code examples
rfloating-pointdivisionmilliseconds

Calculating Time Differences in Milliseconds


I want to rowwise calculate the difference of timestamps in milliseconds. The difference (time_diff) in the example below should always be 0.2, but I am also getting values above and below 0.2.

The problem starts, when dividing the milliseconds to seconds and/or adding numeric values to a POSIXct object.

I assume that it is some floating-point problem, so I tried specifying the amount of digits.sec and digits, rounding, truncating, etc... But the problem remains.

Why is that exactly and how to solve this problem?

library(dplyr)

options("digits.secs"=10)
options(digits = 10)

id <- 1:12
time <- c("9:34:50" , "9:34:50" , "9:34:51" , "9:34:51" , "9:34:51" , "9:34:51" ,
  "9:34:51" , "9:34:52" , "9:34:52" , "9:34:52" , "9:34:52" , "9:34:52")
ms <- c(600,800,0,200,400,600,800,0,200,400,600,800)

time <- as.POSIXct(time, format="%H:%M:%S", tz="GMT")

# Problem begins here
timeNew <- time + (ms/1000)

timeNewDf <- data.frame(id=id,
                      time=timeNew)

timeNewDf %>% dplyr::mutate(
  time_diff = c(diff(time),0)) %>% 
  dplyr::rowwise()

Solution

  • POSIXct will approximate to its nearest floating point less than exact time. Add an offset to cater to floating point approximation and show till 1 digit of milliseconds.

    library(dplyr) 
    options("digits.secs"=1)                                        # showing upto 1 digit
    
    # test data
    id <- 1:12
    time <- c("9:34:50" , "9:34:50" , "9:34:51" , "9:34:51" , "9:34:51" , 
              "9:34:51" , "9:34:51" , "9:34:52" , "9:34:52" , "9:34:52" , "9:34:52" , "9:34:52")
    ms <- c(600,800,0,200,400,600,800,0,200,400,600,800)
    time <- as.POSIXct(time, format="%H:%M:%S", tz="GMT")
    
    # offset to cater to floating point approximations
    timeNew <- time + (ms/1000) + .0001
    
    timeNewDf <- data.frame(id=id, time=timeNew)
    timeNewDf %>% mutate(time_diff = round(c(diff(time),0),1))      # rounding to 1 decimal digit
    
    #1   1 2018-05-30 09:34:50.6  0.2 secs
    #2   2 2018-05-30 09:34:50.8  0.2 secs
    #3   3 2018-05-30 09:34:51.0  0.2 secs
    #4   4 2018-05-30 09:34:51.2  0.2 secs
    #5   5 2018-05-30 09:34:51.4  0.2 secs
    #6   6 2018-05-30 09:34:51.6  0.2 secs
    #7   7 2018-05-30 09:34:51.8  0.2 secs
    #8   8 2018-05-30 09:34:52.0  0.2 secs
    #9   9 2018-05-30 09:34:52.2  0.2 secs
    #10 10 2018-05-30 09:34:52.4  0.2 secs
    #11 11 2018-05-30 09:34:52.6  0.2 secs
    #12 12 2018-05-30 09:34:52.8  0.0 secs