10

以指定单位获取由intervalin表示的时间长度的最佳方法是什么?lubridate我能想到的只是以下混乱的事情:

> ival
[1] 2011-01-01 03:00:46 -- 2011-10-21 18:33:44

> difftime(attr(ival, "start") + as.numeric(ival), attr(ival, "start"), 'days')
Time difference of 293.6479 days

(我还在https://github.com/hadley/lubridate/issues/105上将此作为功能请求添加,假设没有更好的方法可用 - 但也许这里有人知道。)

更新- 显然该difftime函数也不处理这个。这是一个例子。

> (d1 <- as.POSIXct("2011-03-12 12:00:00", 'America/Chicago'))
[1] "2011-03-12 12:00:00 CST"
> (d2 <- d1 + days(1))  # Gives desired result
[1] "2011-03-13 12:00:00 CDT"
> (i2 <- d2 - d1)
[1] 2011-03-12 12:00:00 -- 2011-03-13 12:00:00 
> difftime(attr(i2, "start") + as.numeric(i2), attr(i2, "start"), 'days')
Time difference of 23 hours

正如我在下面提到的,我认为处理这个问题的一种好方法是实现一个/.interval不首先将其输入转换为period.

4

4 回答 4

13

as.duration功能是 lubridate 提供的。间隔类在内部表示为从开始开始的秒数,因此如果您想要小时数,您可以简单地除以as.numeric(ival)3600 或除以 (3600*24) 天。

如果您想要将函数的工作示例应用于您的对象,您应该提供dput(ival) 的输出。我对发送给我的help(duration)页面上创建的对象进行了测试?interval

 date <- as.POSIXct("2009-03-08 01:59:59") # DST boundary
 date2 <- as.POSIXct("2000-02-29 12:00:00")
 span <- date2 - date  #creates interval 
 span
#[1] 2000-02-29 12:00:00 -- 2009-03-08 01:59:59 
 str(span)
#Classes 'interval', 'numeric'  atomic [1:1] 2.85e+08
#  ..- attr(*, "start")= POSIXct[1:1], format: "2000-02-29 12:00:00"
 as.duration(span)
#[1] 284651999s (9.02y) 
 as.numeric(span)/(3600*24)
#[1] 3294.583
# A check against the messy method:
difftime(attr(span, "start") + as.numeric(span), attr(span, "start"), 'days')
# Time difference of 3294.583 days
于 2012-01-06T23:41:15.583 回答
3

肯,除以天数(1)会给你你想要的。当您将间隔除以期间时,Lubridate 不会将期间强制为持续时间。(尽管用于查找区间中整个周期的确切数量的算法确实从使用区间除以持续时间的类似数量的估计开始,这可能是您注意到的)。

最终结果是适合区间的整个周期数。警告消息会提醒用户这是一个估计值,因为会从答案中删除一部分时间段。用一小段时间进行数学运算是不明智的,因为除非我们将其转换为较短周期的倍数,否则我们无法使用它来修改时钟时间 - 但不会有一种一致的方式来进行转换。例如,您提到的那一天等于 23 小时,但其他日子等于 24 小时。您的想法是正确的 - 周期是为了尊重 DST、闰年等造成的变化,但它们只是作为一个整体来做。

我无法重现您上面提到的减法错误。它似乎对我有用。

    three <- force_tz(ymd_hms("2011-03-12 12:00:00"), "") 
    # note: here in TX, "" *is* CST
    (four <- three + days(1))
    > [1] "2011-03-13 12:00:00 CDT"
    four - days(1)
    > [1] "2011-03-12 12:00:00 CST"
于 2012-01-09T19:19:11.210 回答
3

这个问题真的很老,但我正在添加更新,因为这个问题已经被查看过很多次,当我今天需要做这样的事情时,我找到了这个页面。lubridate您现在可以执行以下操作:

d1 <- ymd_hms("2011-03-12 12:00:00", tz = 'America/Chicago')
d2 <- ymd_hms("2011-03-13 12:00:00", tz = 'America/Chicago')

(d1 %--% d2)/dminutes(1)
(d1 %--% d2)/dhours(1)
(d1 %--% d2)/ddays(1)
(d1 %--% d2)/dweeks(1)
于 2020-10-05T12:42:10.680 回答
1

以秒为单位计算时间以获得天数时要小心,因为那时您不再使用抽象的时间表示,而是使用裸数字,这可能导致以下结果:

> date_f <- now()
> date_i <- now() - days(23)
> as.duration(date_f - date_i)/ddays(1)
[1] 22.95833
> interval(date_i,date_f)/ddays(1)
[1] 22.95833
> int_length(interval(date_i,date_f))/as.numeric(ddays(1))
[1] 22.95833

这导致认为天或月是日历中的事件,而不是可以以秒、毫秒等为单位测量的时间量。

计算天数差异的最佳方法是避免转换为秒并以天为单位工作:

> e <- now()
> s <- now() - days(23)  
> as.numeric(as.Date(s))
[1] 18709
> as.numeric(as.Date(e) - as.Date(s))
[1] 23

但是,如果您将一天视为纯 86400 秒的时间跨度,ddays()那么前面的方法可能会导致以下结果:

> e <- ymd_hms("2021-03-13 00:00:10", tz = 'UTC')
> s <- ymd_hms("2021-03-12 23:59:50", tz = 'UTC')
> as.duration(e - s)
[1] "20s"
> as.duration(e - s)/ddays(1)
[1] 0.0002314815
> as.numeric(as.Date(e) - as.Date(s))
[1] 1

因此,这取决于您要查找的内容:时差或日历差。

于 2021-04-15T08:24:11.777 回答