R:xts时间戳与实际数据时间戳相差1毫秒

时间:2018-05-03 13:44:40

标签: r xts

所以我有以下数据。

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行中的毫秒数不正确。

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

1 个答案:

答案 0 :(得分:2)

这类似于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 ±0.0005,因为对它们进行舍入有不同的规则,表示时间点的实际浮点数将比这更接近所需的值。

编辑:关于差异的评论中的问题:如果将其添加到两个点,是否添加半毫秒并不重要。具有需要自行调整的时间点的示例:

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