为了账号安全,请及时绑定邮箱和手机立即绑定

R如何用小数秒格式化POSIXct

R如何用小数秒格式化POSIXct

手掌心 2019-08-27 13:39:23
R如何用小数秒格式化POSIXct我认为R错误地使用小数秒格式化POSIXct类型。我通过R-bugs作为增强请求提交了这个,并且“我们认为当前的行为是正确的 - 删除了bug”。虽然我非常感谢他们已经完成并将继续做的工作,但我想让其他人对这个特定问题采取行动,并且可能就如何更有效地提出要点提出建议。这是一个例子: > tt <- as.POSIXct('2011-10-11 07:49:36.3')  > strftime(tt,'%Y-%m-%d %H:%M:%OS1')  [1] "2011-10-11 07:49:36.2"也就是说,tt被创建为POSIXct时间,小数部分.3秒。当使用一个十进制数字打印时,显示的值为.2。我使用毫秒级精度的时间戳工作很多,这让我很烦恼,因为时间通常比实际值低一个等级。以下是发生的事情:POSIXct是自纪元以来的浮点秒数。精确处理所有整数值,但在base-2浮点中,与.3最接近的值略小于.3。strftime()格式的所述行为%OSn是向下舍入到请求的小数位数,因此显示的结果为.2。对于其他小数部分,浮点值略高于输入的值,显示屏给出预期结果: > tt <- as.POSIXct('2011-10-11 07:49:36.4')  > strftime(tt,'%Y-%m-%d %H:%M:%OS1')  [1] "2011-10-11 07:49:36.4"开发人员的论点是,对于时间类型,我们应该总是向下舍入到请求的精度。例如,如果时间是11:59:59.8,那么用格式打印它%H:%M应该给出“11:59”而不是“12:00”,并且%H:%M:%S 应该给出“11:59:59”而不是“12:00:00”。我同意这个整数秒和格式标志%S,但我认为对于为秒的小数部分设计的格式标志,行为应该是不同的。我希望看到%OSn使用舍入到最近的行为,即使是n = 0同时%S使用循环下来,从而使打印11:59:59.8与格式%H:%M:%OS0会给“12:00:00”。这不会影响整数秒的任何事情,因为它们总是精确地表示,但它会更自然地处理小数秒的舍入误差。这就是如何处理小数部分的打印,例如C,因为整数转换向下舍入: double x = 9.97;  printf("%d\n",(int) x);   //  9  printf("%.0f\n",x);       //  10  printf("%.1f\n",x);       //  10.0  printf("%.2f\n",x);       //  9.97我做了一个关于如何在其他语言和环境中处理小数秒的快速调查,并且似乎确实没有达成共识。大多数构造设计为整数秒,而小数部分是事后想法。在我看来,在这种情况下,R开发人员做出的选择并非完全不合理,但实际上并不是最好的选择,并且与其他地方用于显示浮点数的约定不一致。人们的想法是什么?R行为是否正确?这是你自己设计它的方式吗?
查看完整描述

2 回答

?
慕尼黑8549860

TA贡献1818条经验 获得超11个赞


一个潜在的问题是POSIXct表示不如POSIXlt表示精确,并且POSIXct表示在格式化之前转换为POSIXlt表示。下面我们看到如果我们的字符串直接转换为POSIXlt表示,它输出正确。


> as.POSIXct('2011-10-11 07:49:36.3')

[1] "2011-10-11 07:49:36.2 CDT"

> as.POSIXlt('2011-10-11 07:49:36.3')

[1] "2011-10-11 07:49:36.3"

我们还可以通过查看两种格式的二进制表示与0.3的通常表示之间的差异来看到。


> t1 <- as.POSIXct('2011-10-11 07:49:36.3')

> as.numeric(t1 - round(unclass(t1))) - 0.3

[1] -4.768372e-08


> t2 <- as.POSIXlt('2011-10-11 07:49:36.3')

> as.numeric(t2$sec - round(unclass(t2$sec))) - 0.3

[1] -2.831069e-15

有趣的是,看起来两个表示实际上都比0.3的通常表示要小,但是第二个表示要么足够接近,要么截断的方式与我想象的不同。鉴于此,我不会担心浮点表示困难; 它们可能仍然会发生,但如果我们小心使用哪种表示方式,它们有望最小化。


罗伯特对圆形输出的渴望只是输出问题,可以通过多种方式解决。我的建议是这样的:


myformat.POSIXct <- function(x, digits=0) {

  x2 <- round(unclass(x), digits)

  attributes(x2) <- attributes(x)

  x <- as.POSIXlt(x2)

  x$sec <- round(x$sec, digits)

  format.POSIXlt(x, paste("%Y-%m-%d %H:%M:%OS",digits,sep=""))

}

这从POSIXct输入开始,并首先轮到所需的数字; 然后转换为POSIXlt并再次舍入。第一轮舍入确保当我们处于分钟/小时/天边界时所有单元都适当增加; 转换为更精确的表示后的第二轮四舍五入。


> options(digits.secs=1)

> t1 <- as.POSIXct('2011-10-11 07:49:36.3')

> format(t1)

[1] "2011-10-11 07:49:36.2"

> myformat.POSIXct(t1,1)

[1] "2011-10-11 07:49:36.3"


> t2 <- as.POSIXct('2011-10-11 23:59:59.999')

> format(t2)

[1] "2011-10-11 23:59:59.9"

> myformat.POSIXct(t2,0)

[1] "2011-10-12 00:00:00"

> myformat.POSIXct(t2,1)

[1] "2011-10-12 00:00:00.0"

最后一个:你知道标准允许最多两个闰秒吗?


> as.POSIXlt('2011-10-11 23:59:60.9')

[1] "2011-10-11 23:59:60.9"

好的,还有一件事。由于OP提交的错误,该行为实际上在5月发生了变化(错误14579); 在那之前,它确实是小数秒。不幸的是,这意味着有时它可以绕到一秒钟是不可能的; 在错误报告中,当它应该转到下一分钟时,它上升到60。决定截断而不是舍入的一个原因是它是从POSIXlt表示打印的,其中每个单元是分开存储的。因此,滚动到下一分钟/小时/等比仅仅简单的舍入操作更困难。要轻松舍入,有必要在POSIXct表示中进行舍入,然后按照我的建议转换回来。


查看完整回答
反对 回复 2019-08-27
  • 2 回答
  • 0 关注
  • 957 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信