【问题标题】:R: xts timestamp differ from real data timestamp by 1 millisecondR:xts 时间戳与真实数据时间戳相差 1 毫秒
【发布时间】:2018-05-03 13:44:40
【问题描述】:

所以我有以下数据。

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", "2018-03-01 09:51:59.971", "2018-03-01 09:51:59.987", 
"2018-03-01 09:51:59.988"), Mid_Px = c(30755.5, 30755, 30755.5, 
30756, 30756.5, 30756.5)), .Names = c("Timestamp", "Mid_Px"), class = "data.frame", row.names = 85774:85779)

看起来像这样:

                    Timestamp  Mid_Px
85774 2018-03-01 09:51:59.969 30755.5
85775 2018-03-01 09:51:59.969 30755.0
85776 2018-03-01 09:51:59.970 30755.5
85777 2018-03-01 09:51:59.971 30756.0
85778 2018-03-01 09:51:59.987 30756.5
85779 2018-03-01 09:51:59.988 30756.5

当我尝试使用下面的代码从中创建一个 xts 对象时,事情开始变得糟糕。

tt_ts <- strptime(tt[,1],"%Y-%m-%d %H:%M:%OS")
tt_ts
[1] "2018-03-01 09:51:59.969 CST" "2018-03-01 09:51:59.969 CST" "2018-03-01 09:51:59.970 CST" "2018-03-01 09:51:59.971 CST" "2018-03-01 09:51:59.987 CST"
[6] "2018-03-01 09:51:59.988 CST"
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.970 30756.0
2018-03-01 09:51:59.986 30756.5
2018-03-01 09:51:59.987 30756.5

注意第 4,5 和 6 行的毫秒数不正确。

我在这里做错了什么?如何修复它以显示正确的时间戳?

【问题讨论】:

    标签: r xts


    【解决方案1】:

    这类似于R issue with rounding milliseconds。一种简单的解决方案是按照那里的建议添加 0.5 毫秒:

    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
    

    我们可以从一个简单的例子中看出这一点:

    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"
    

    转换为POSIXct 后,ms 错误。提高输出精度,我们看到用来表示时间的浮点数刚好低于要求的值,但是 R 将数字截断而不是四舍五入:

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

    移动所需精度的一半可以解决此问题。

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

    一般情况下,如果x是一个3位小数,任何在开放范围内的数(x - 0.0005, x + 0.0005 ) 将四舍五入为 x。在截断时,这仍然适用于 [x, x + 0.0005) 内的那些。但是如您所见, (x - 0.0005, x) 内的那些将由 x - 0.001 表示。如果我们在截断前将相关数字移动 0.0005,我们说的是范围 (x, x + 0.001)。所有这些数字都将根据需要截断为 x

    我排除了点x &pm; 0.0005,因为有不同的四舍五入规则,代表时间点的实际浮点数将比这更接近期望值。

    编辑:关于 cmets 中关于取差的问题:如果将它添加到两个点,是否添加半毫秒都无关紧要。需要自行调整时间点的示例:

    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"
    

    还有一个不需要调整的时间点:

    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"
    

    差异是相同的,不受任何调整的影响:

    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.0005 是否适用于所有时间戳。谢谢。
    • @mynameisJEFF 从我的角度来看,这是一般性的,请参阅扩展答案。
    • 我有一个问题:如果我要在这种情况下计算时间戳之间的时间差,我应该做difftime(t1+0.0005, t2+0.0005, units="secs") 吗?是否需要在两个时间戳中都加上0.0005才能保证时差计算正确?
    • @mynameisJEFF 如果您要计算差异,则无需添加 0.0005,请参见我的扩展答案。
    猜你喜欢
    • 1970-01-01
    • 2016-03-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-25
    • 1970-01-01
    • 2016-03-04
    相关资源
    最近更新 更多