在interval
中以指定单位获得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
。
答案 0 :(得分:10)
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
答案 1 :(得分: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"
答案 2 :(得分:1)
这个问题确实很老,但是我要添加一个更新,因为这个问题已经被浏览了很多次,并且当我今天需要做这样的事情时,我找到了这个页面。现在,您可以在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)
答案 3 :(得分: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
但是,如果您像 ddays()
一样将一天视为纯 86400 秒的时间跨度,则之前的方法可能会导致以下结果:
> 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
因此,这取决于您要查找的内容:时差或日历差。