R: xts timestamp differ from real data timestamp by 1 millisecond

后端 未结 1 668
不知归路
不知归路 2021-01-24 00:54

So I have the following data.

tt <- structure(list(Timestamp = c(\"2018-03-01 09:51:59.969\", \"2018-03-01 09:51:59.969\", 
\"2018-03-01 09:51:59.970\", \"20         


        
相关标签:
1条回答
  • 2021-01-24 01:12

    This is similar to R issue with rounding milliseconds. One simple solution would be adding 0.5 ms as suggested there:

    tt_ts <- strptime(tt[,1],"%Y-%m-%d %H:%M:%OS") + 0.0005
    xts::xts(x=tt[,c(-1)], order.by=tt_ts)
    #                            [,1]
    # 2018-03-01 09:51:59.969 30755.5
    # 2018-03-01 09:51:59.969 30755.0
    # 2018-03-01 09:51:59.970 30755.5
    # 2018-03-01 09:51:59.971 30756.0
    # 2018-03-01 09:51:59.987 30756.5
    # 2018-03-01 09:51:59.988 30756.5
    

    We can see this from a simple example:

    st <- strptime("2018-03-01 09:51:59.971", "%Y-%m-%d %H:%M:%OS")
    format(st, "%Y-%m-%d %H:%M:%OS3")
    #> [1] "2018-03-01 09:51:59.971"
    pt <- as.POSIXct(st)
    format(pt, "%Y-%m-%d %H:%M:%OS3")
    #> [1] "2018-03-01 09:51:59.970"
    

    After conversion to POSIXct the ms is wrong. Increasing the output precision, we see that the floating point number used to represent the time is just below the required value, but R truncates the number instead of rounding it:

    format(pt, "%Y-%m-%d %H:%M:%OS6")
    #> [1] "2018-03-01 09:51:59.970999"
    

    Shifting by one half of the required precision fixes this.

    format(pt + 0.0005, "%Y-%m-%d %H:%M:%OS3")
    #> [1] "2018-03-01 09:51:59.971"
    

    Generally, if x is a number with 3 decimal digits, any number within the open range (x - 0.0005, x + 0.0005) would be rounded to x. On truncation, that would still work for those within [x, x + 0.0005). But those within (x - 0.0005, x) would be represented by x - 0.001 as you observed. If we shift the relevant number by 0.0005 before truncation, we are speaking about the range (x, x + 0.001). All these numbers will be truncated to x as wanted.

    I am excluding the points x ± 0.0005 since there are different rules for rounding them and the actual floating point number representing the time point will be a lot closer to the desired value than this.

    EDIT: Concerning the question in the comments about taking differences: There it should not matter whether you add half a milli-second or not if you add it to both points. Example with a time point that needs adjustment on its own:

    st1 <- strptime("2018-03-01 09:51:59.971", "%Y-%m-%d %H:%M:%OS")
    format(st1, "%Y-%m-%d %H:%M:%OS3")                              
    #> [1] "2018-03-01 09:51:59.970"
    pt1 <- as.POSIXct(st1)                                          
    format(pt1, "%Y-%m-%d %H:%M:%OS3")                              
    #> [1] "2018-03-01 09:51:59.970"
    format(pt1 + 0.0005, "%Y-%m-%d %H:%M:%OS3")                     
    #> [1] "2018-03-01 09:51:59.971"
    

    And a time point that does not need adjustment:

    st2 <- strptime("2018-03-01 09:51:59.969", "%Y-%m-%d %H:%M:%OS")
    format(st2, "%Y-%m-%d %H:%M:%OS3")                              
    #> [1] "2018-03-01 09:51:59.969"
    pt2 <- as.POSIXct(st2)                                          
    format(pt2, "%Y-%m-%d %H:%M:%OS3")                              
    #> [1] "2018-03-01 09:51:59.969"
    format(pt2 + 0.0005, "%Y-%m-%d %H:%M:%OS3")                     
    #> [1] "2018-03-01 09:51:59.969"
    

    Difference is the same independent of any adjustment:

    difftime(pt1, pt2, "secs")                                      
    #> Time difference of 0.001999855 secs
    difftime(pt1 + 0.0005, pt2 + 0.0005, "secs")                    
    #> Time difference of 0.001999855 secs
    
    0 讨论(0)
提交回复
热议问题