6
options(digits.secs = 3);

> strptime("2007-03-30 15:00:00.007", format = "%Y-%m-%d %H:%M:%OS");
[1] "2007-03-30 15:00:00.007"
> strptime("2007-03-30 15:00:00.008", format = "%Y-%m-%d %H:%M:%OS");
[1] "2007-03-30 15:00:00.008"
> strptime("2007-03-30 15:00:00.009", format = "%Y-%m-%d %H:%M:%OS");
[1] "2007-03-30 15:00:00.008"
> strptime("2007-03-30 15:00:00.010", format = "%Y-%m-%d %H:%M:%OS");
[1] "2007-03-30 15:00:00.01"
> strptime("2007-03-30 15:00:00.011", format = "%Y-%m-%d %H:%M:%OS");
[1] "2007-03-30 15:00:00.010"
> strptime("2007-03-30 15:00:00.999", format = "%Y-%m-%d %H:%M:%OS");
[1] "2007-03-30 15:00:00.998"

我很困惑为什么与“009”相差一毫秒,然后又与“011”相差一毫秒。

4

2 回答 2

9

这与R-FAQ 7.31相关,尽管它采用了不同寻常的伪装。

您看到的行为是以下组合的结果:(a)二进制计算机对(大多数)十进制值的不精确表示;(b) 和 的记录行为strftimestrptime它是将秒的小数部分截断而不是四舍五入到指定的小数位数。

?strptime帮助文件(关键字被“截断”):

特定于 R 的是 '%OSn',它对于输出给出截断为 '0 <= n <= 6' 小数位的秒数(如果 '%OS' 后面没有数字,它使用 'getOption( “digits.secs”)',或者如果未设置,则为 'n = 3')。

一个例子可能会比进一步解释更有效地说明正在发生的事情:

strftime('2011-10-11 07:49:36.3', format="%Y-%m-%d %H:%M:%OS6")
[1] "2011-10-11 07:49:36.299999"

strptime('2012-01-16 12:00:00.3', format="%Y-%m-%d %H:%M:%OS1")
[1] "2012-01-16 12:00:00.2"

在上面的例子中,小数 '.3' 必须用一个略小于 '0.300000000000000000' 的二进制数来近似,比如 '0.29999999999999999'。因为strptimestrftime截断而不是舍入到指定的小数位,如果小数位数设置为 1,0.3 将转换为 0.2。相同的逻辑适用于您的示例时间,其中一半表现出这种行为,就像(在平均)预期。

于 2012-01-17T07:03:59.677 回答
3

我知道它已被“回答”,但这个问题对于 32 位 R 仍然存在,32 位和 64 位版本之间的实现存在不一致。截断问题部分正确,但在这种特殊情况下,它不是 strptime 函数的结果,而是 print.POSIXlt 方法的结果。

这可以通过用产生预期行为的函数覆盖函数来证明。例如

print.POSIXlt = function(posix) {
    print(paste0(posix$year+1900,"-",sprintf("%02d",posix$mon+1),"-",sprintf("%02d",posix$mday)," ",
       sprintf("%02d",posix$hour),":",sprintf("%02d",posix$min),":",sprintf("%002.003f",posix$sec)))
    }

现在时间按预期显示:

> strptime("2007-03-30 15:00:00.009", format = "%Y-%m-%d %H:%M:%OS");
[1] "2007-03-30 15:00:0.009"

有关更多详细信息,我在这里用舍入毫秒讨论了这个 R 问题

于 2015-10-16T01:11:19.533 回答