首页 > 解决方案 > 如何安全地存储时间戳之间的毫秒差异?

问题描述

这是与 R 中的浮点近似和时间戳相关的一些地狱般的问题。准备好:) 考虑这个简单的例子:

library(tibble)
library(lubridate)
library(dplyr)

tibble(timestamp_chr1 = c('2014-01-02 01:35:50.858'),
       timestamp_chr2 = c('2014-01-02 01:35:50.800')) %>% 
  mutate(time1 = lubridate::ymd_hms(timestamp_chr1),
         time2 = lubridate::ymd_hms(timestamp_chr2),
         timediff = as.numeric(time1 - time2))


# A tibble: 1 x 5
  timestamp_chr1          timestamp_chr2          time1                      time2                       timediff
  <chr>                   <chr>                   <dttm>                     <dttm>                         <dbl>
1 2014-01-02 01:35:50.858 2014-01-02 01:35:50.800 2014-01-02 01:35:50.858000 2014-01-02 01:35:50.799999 0.0580001

这里两个时间戳之间的时间差显然是58毫秒,但是 R 用一些浮点近似值存储它,以便它显示为0.058001秒。

什么是获得精确 58毫秒作为 asnwer 的最安全方法?我考虑过使用as.integer(而不是as.numeric),但我担心会丢失一些信息。在这里可以做什么?

谢谢!

标签: rfloating-pointtimestamplubridatenanotime

解决方案


一些考虑,一些我想你已经知道了:

  • 浮点很少会给你完美的58 毫秒(由于 R FAQ 7.31 和 IEEE-754);

  • 数据的显示可以在控制台上用options(digits.secs=3)(and digits=3) 管理,在报告中用sprintf, format, or round;

  • 如果在计算前四舍五入,可以提高计算“好”;虽然这有点繁琐,但只要我们可以安全地假设数据至少精确到毫秒,这在数学上是成立的。

但是,如果您担心在数据中引入错误,另一种方法是编码为毫秒(而不是 R 规范的秒数)。如果您可以选择任意和最近(24 天以下)的参考点,那么您可以使用 normal 来完成integer,但如果这还不够或者您更喜欢使用epoch milliseconds,那么您需要跳转到 64 位整数,也许使用bit64.

now <- Sys.time()
as.integer(now)
# [1] 1583507603
as.integer(as.numeric(now) * 1000)
# Warning: NAs introduced by coercion to integer range
# [1] NA
bit64::as.integer64(as.numeric(now) * 1000)
# integer64
# [1] 1583507603439

推荐阅读