diff 下 POSIXct 日期时间的意外行为

Unexpected behavior with POSIXct datetimes under diff

将 diff() 应用于 POSIXct 日期时间时,会得到意想不到的结果。差异的单位并不总是相同的。

在每小时递增的 POSIXct 日期时间上,diff() 按预期工作。如果小时数是连续的,diff 会给出小时差,如下所示。

beg = ISOdatetime(2016, 11, 6, 1, 0 ,0, tz="Americ/Los_Angeles")
end = ISOdatetime(2016, 11, 7, 23, 0 ,0, tz="Americ/Los_Angeles")
dte = seq(from=beg, to=end, by="hour")
del = diff(dte)
table(del)
del
  1 
 46 

如果有差距,结果还是以小时为单位,这是有道理的。

dte = dte[-4]
del = diff(dte)
table(del)
 del
 1  2 
44  1

现在,这是有趣的行为。

dte1 = sort(c(dte, dte[10]))
del = diff(dte1)
table(del)
del
 0 3600 7200 
 1   44    1 

我在这里添加了一个重复的小时,突然之间,diff 单位现在变成了秒。

这是一个错误吗?

difftime 对象有一个 units<- 函数:

> units(del) <- 'hours'
> table(del)
del
 0  1 
 1 46 

?difftime 帮助页面说:

If units = "auto", a suitable set of units is chosen, the largest possible (excluding "weeks") in which all the absolute differences are greater than one.

因此,在您的案例中,函数的逻辑可能被 0 值偏离,单位设置为秒。

如果您阅读 diff.POSIXt 的源代码,它包含代码

r <- r[i1] - r[-length(r):-(length(r) - lag + 1L)]

其中 r 是 POSIXct 序列,i1

定义
i1 <- -seq_len(lag)

如果 lag 参数默认为 1,则为 -1。因此,diff(dte1) 等同于

dte1[-1L] - dte1[-length(dte1):-(length(dte1) - 1L + 1L)]

您可以将其简化为

dte1[-1L] - dte1[-length(dte1)]

如果您查看 ?difftime,您会看到

Subtraction of date-time objects gives an object of this class, by calling difftime with units = "auto".

units = "auto" 调用 difftime 通过

确定单位

If units = "auto", a suitable set of units is chosen, the largest possible (excluding "weeks") in which all the absolute differences are greater than one.

这可能会有所不同。如果你想要特定的单位,你可以直接用difftime重建操作:

difftime(dte1[-1], dte1[-length(dte1)], units = 'hours')

## Time differences in hours
##  [1] 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
## [47] 1 1