从具有亚毫秒日期时间的字符->POSIXct->字符准确转换

Accurately converting from character->POSIXct->character with sub millisecond datetimes

提问人:statquant 提问时间:3/13/2013 最后编辑:Communitystatquant 更新时间:8/11/2018 访问量:9939

问:

我的文件中有一个字符日期时间列。我将文件(加载到 )中,并执行需要将列转换为 的操作。然后我需要将值写回文件,但日期时间不会相同(因为它打印不正确)。data.tablePOSIXctPOSIXct

这个打印/格式问题是众所周知的,并且已经讨论过几次。我读过一些描述这个问题的帖子。我找到的最权威的答案是针对这个问题给出的。该问题的答案提供了两个函数 ( 和 ) 来解决这个问题,但它们似乎不适用于此示例:myformat.POSIXctform

x <- "04-Jan-2013 17:22:08.139"
options("digits.secs"=6)
form(as.POSIXct(x,format="%d-%b-%Y %H:%M:%OS"),format="%d-%b-%Y %H:%M:%OS3")
[1] "04-Jan-2013 17:22:08.138"
form(as.POSIXct(x,format="%d-%b-%Y %H:%M:%OS"),format="%d-%b-%Y %H:%M:%OS4")
[1] "04-Jan-2013 17:22:08.1390"
myformat.POSIXct(as.POSIXct(x,format="%d-%b-%Y %H:%M:%OS"),digits=3)
[1] "2013-01-04 17:22:08.138"
myformat.POSIXct(as.POSIXct(x,format="%d-%b-%Y %H:%M:%OS"),digits=4)
[1] "2013-01-04 17:22:08.1390"

我:sessionInfo

R version 2.15.2 (2012-10-26)
Platform: x86_64-w64-mingw32/x64 (64-bit)

locale:
[1] LC_COLLATE=English_United Kingdom.1252  LC_CTYPE=English_United Kingdom.1252
[3] LC_MONETARY=English_United Kingdom.1252 LC_NUMERIC=C                        
[5] LC_TIME=C                              

attached base packages:
[1] stats     graphics  grDevices datasets  utils     methods   base     

other attached packages:
[1] fasttime_1.0-0   data.table_1.8.9 bit64_0.9-2      bit_1.1-9
[5] sas7bdat_0.3     chron_2.3-43     vimcom_0.9-6    

loaded via a namespace (and not attached):
[1] tools_2.15.2
r posixct

评论

0赞 Matthew Lundberg 3/14/2013
对于这个日期,两者的功能和执行基本相同的操作,将秒值四舍五入到三位。但是 0.139 不能准确表示(.1389999 是我在调试器中看到的舍入值的小数部分),因此截断仍然存在。请注意,139 是素数(因此相对于 2 和 5 而言)。form()myformat.POSIXct

答:

3赞 Dirk Eddelbuettel 3/13/2013 #1

当你写的时候

我的理解是 POSIXct 表示不如 POSIXlt 表示形式

你大错特错了。

两者的表示形式相同——在 Windows 上低至毫秒,在其他操作系统上低至(几乎)微。你读过吗?help(DateTimeClasses)

至于你的最后一个问题,是的,我的 RcppBDT 包的开发版本使用 Boost Date.Time,如果您的操作系统支持它并且您打开了正确的表示,它可以一直到纳秒。但它确实取代了 POSIXct,并且还不支持时间对象的向量。

编辑:关于您的后续问题:

R> one <- Sys.time(); two <- Sys.time(); two - one
Time difference of 7.43866e-05 secs
R>
R> as.POSIXlt(two) - as.POSIXlt(one)
Time difference of 7.43866e-05 secs
R> 
R> one    # options("digits.sec"=6) on my box
[1] "2013-03-13 07:30:57.757937 CDT"
R> 

编辑2:我认为您只是在体验计算机上的浮点表示是不准确的:

R> print(as.numeric(as.POSIXct("04-Jan-2013 17:22:08.138",
+                   format="%d-%b-%Y %H:%M:%OS")), digits=18)
[1] 1357341728.13800001
R> print(as.numeric(as.POSIXct("04-Jan-2013 17:22:08.139",
+                   format="%d-%b-%Y %H:%M:%OS")), digits=18)
[1] 1357341728.13899994
R> 

差异并不像您假设的那样恰好是 1/1000。

评论

0赞 statquant 3/13/2013
你好德克,就代表而言,你确定吗?我编辑了引用另一篇文章来说明我的意思。我红色它和一样,我没有看到任何特定于 Windows 的东西。由于您似乎已经深入研究了这些问题,因此如何使用 POSIXct 正确表示毫秒日期时间?help(DateTimeClass)?POSIXltPOSIXct
0赞 statquant 3/13/2013
Dirk,您关于 Windows 与其他操作系统的声明有任何参考吗?
0赞 Dirk Eddelbuettel 3/13/2013
请重新阅读我的原始答案。Windows --仅 > 毫秒。
1赞 Aaron left Stack Overflow 3/14/2013
嗨,Dirk,我认为就浮点表示而言,POSIXct 确实不太精确;它必须将更多的有效数字放入相同的大小中,因为它具有自 1970 年以来的秒数加上任何小数部分;由于 POSIXlt 将秒数分成自己的数字,因此有效数字较少,因此浮点表示可以更精确。@statquant指的是我在这里的回答 stackoverflow.com/a/7730759/210673 它举了一个例子。numeric
0赞 Dirk Eddelbuettel 3/15/2013
@statquant:我认为这是错误的。POSIXct 是 64 位双拆分为 53 位和 11 位。显示 40 位声明的源文件或 R 内部/R 语言手册。
4赞 Joshua Ulrich 3/13/2013 #2

正如您链接到的问题的答案已经说过的那样,值的打印/格式与实际值不同这只是一个印刷的表示问题。

R> as.POSIXct('2011-10-11 07:49:36.3')-as.POSIXlt('2011-10-11 07:49:36.3')
Time difference of 0 secs
R> as.POSIXct('2011-10-11 07:49:36.2')-as.POSIXlt('2011-10-11 07:49:36.3')
Time difference of -0.0999999 secs

你的理解不那么精确,而不是不正确。您说不能将对象作为列包含在 data.frame 中也是不正确的。POSIXctPOSIXltPOSIXlt

R> x <- data.frame(date=Sys.time())
R> x$date <- as.POSIXlt(x$date)
R> str(x)
'data.frame':   1 obs. of  1 variable:
 $ date: POSIXlt, format: "2013-03-13 07:38:48"

评论

0赞 Joshua Ulrich 3/13/2013
@statquant:因为这是另一个问题,而不是答案。
0赞 statquant 3/13/2013
好的表示,对于包含在 data.frame 中,我的意思是 data.table。我引用的帖子提供了有关如何解决此表示问题的建议,但是对于 04-01-2013 17:22:08.139,它似乎失败了(请参阅我的编辑)。有没有办法从 POSIXct 获得准确的表示(毫秒级)?
0赞 Joshua Ulrich 3/13/2013
@statquant:这是准确的。您仍然将实际打印的内容混淆。POSIXct
0赞 statquant 3/13/2013
不,我不是,我实际上是在问如何准确打印 POSIXct 对象的时间。假设我在一个文件中有一个字符 datetime 列,我加载文件并执行需要将该列强制转换为 POSIXct 的事情,如果我需要写回文件,日期时间将不相同(打印错误)
1赞 Joshua Ulrich 3/13/2013
@statquant:我明白了。这是一个明确表达的问题。你能编辑你的问题以删除所有无关的散文、其他帖子的引用以及你对解决方案的猜测吗?留下您的输入和期望输出的示例,我相信有人会提供答案。
5赞 Aaron left Stack Overflow 3/14/2013 #3

所以我想你确实需要在我的建议中添加一点软糖因素:https://stackoverflow.com/a/7730759/210673。这似乎有效,但可能包括其他错误;在用于任何重要的事情之前,请仔细测试并考虑它在做什么。

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) + 10^(-digits-1)
  format.POSIXlt(x, paste("%Y-%m-%d %H:%M:%OS",digits,sep=""))
}

评论

0赞 Matthew Lundberg 3/14/2013
你的软糖因素在这里看起来不错。可以在循环中对此进行测试,至少对于小数字值是这样。哦,我完全偷了你的软糖因素。我将其添加到另一个相同问题的答案中,并将在实际代码中使用它。
0赞 Aaron left Stack Overflow 3/14/2013
很高兴你认为它看起来不错。这似乎是一件合理的事情,但我没有花时间仔细考虑。
0赞 statquant 3/14/2013
好消息是,它看起来适用于我的 1.5M 训练集(毫秒)。看起来它很慢,但希望如果修复是好的,它可能被用来修复 POSIXct 在 C 级别显示(我的意思是打印)日期时间的方式......
0赞 Aaron left Stack Overflow 3/14/2013
我实际上怀疑所有代码都在这里添加了软糖因素。我四舍五入了两圈,因为我认为这会让软糖因素变得不需要,但你发现我错了。最初将软糖因子四舍五入并添加到 POSIXct 中,然后打印可能就足够了。
0赞 Aaron left Stack Overflow 3/14/2013
另外,请继续关注 R 的下一个版本;在对另一个问题的评论中,您会看到他们似乎在默认打印代码本身中添加了软糖因子。
3赞 Martin Mächler 8/11/2018 #4

两件事:

1)@statquant是对的(Ulrich和@Dirk Eddelbuettel@Joshua其他知名专家是错的),并且在他的评论中@Aaron,但这对于这里的主要问题并不重要:

POSIXlt从设计上讲,在存储时间方面肯定比 : 由于它的秒数始终在 [0, 60] 中,因此它的粒度约为 6e-15,即 6 飞秒,这比 .POSIXctPOSIXct

但是,这与此处(以及当前的 R)不是很相关:几乎所有操作,尤其是数字操作,都使用 group 方法(是的,初学者不知道,但有据可查),看看哪个确实通过首先强制 .此外,format()/print() ing 在 “.” 之后最多使用 6 个小数点,因此也不区分 的内部较高精度和 “仅” 100 纳秒粒度。
(由于上述原因,Dirk 和 Joshua 都得出了他们的错误断言:对于所有简单的实际用途,*lt 和 *ct 的精度是相同的)。
OpsOps.POSIXtPOSIXctPOSIXltPOSIXct

2)我确实倾向于同意我们(R Core)应该改进这些秒数POSIXt对象的ing,从而改进(仍然在@Aaron上面提到的错误修复之后)。
但是我可能错了,而“我们”已经做对了,根据“正确”的某种定义;-)
format()print()