round_date() 函数 returns floor_date 而不是四舍五入的日期

round_date() function returns floor_date instead of rounded date

使用相关问题中的示例:

library(lubridate)
library(dplyr)

dt<-data.frame(orig_dt=as.Date(c("1997-04-01","1997-06-29")))
dt %>% mutate(round_dt=round_date(orig_dt, unit="month"),
              modified_dt=round_date(orig_dt, unit="month")-days(1))

在一个会话中我正确地得到了四舍五入的日期(R 4.0.0,Rcpp_1.0.4.6 通过命名空间加载)

     orig_dt   round_dt modified_dt
1 1997-04-01 1997-04-01  1997-03-31
2 1997-06-29 1997-07-01  1997-06-30

在另一个会话中,我得到了 floor 而不是 round(不同的机器,R 4.0.2,Rcpp 未通过命名空间加载)

     orig_dt   round_dt modified_dt
1 1997-04-01 1997-04-01  1997-03-31
2 1997-06-29 1997-06-01  1997-05-31

我认为这可能与 Rcpp 有关,因为之前我收到了错误消息

Error in C_valid_tz(tzone) (rscrpt.R#27): function 'Rcpp_precious_remove' not provided by package 'Rcpp'
Show stack trace

虽然我没有再收到错误,但值不同,我想 why/how 修复它而不通过完全重新安装。

我能够在原始 R 会话中重现您的问题。

$ R --vanilla
> packageVersion("lubridate")
[1] ‘1.8.0’
> library("lubridate")
> round_date(x = as.Date("1997-06-29"), unit = "month")
[1] "1997-06-01"

这似乎是 round_date 中的错误,在 this commit 中引入。在提交之前,round_date 的正文包含:

above <- unclass(as.POSIXct(ceiling_date(x, unit = unit, week_start = week_start)))
mid <- unclass(as.POSIXct(x))
below <- unclass(as.POSIXct(floor_date(x, unit = unit, week_start = week_start)))

这里,belowmidabove定义为从1970-01-01 00:00:00 UTCx月底的秒数, xx 的月上限(更准确地说,这三个日期的时间 ​​00:00:00,在您的系统时区中)。因此,below < mid < aboveround_date 将比较 mid-belowabove-mid 以确定 belowabove 中哪个更接近 mid .

自提交以来,mid 已定义为

mid <- unclass(x)

这是从 1970-01-01x 的天数。现在,mid << below < above,使 mid-below 为负,above-mid 为正。因此,round_date 认为 belowabove 更“接近”mid,并且错误地将 1997-06-29 向下舍入为 1997-06-01

我已经向软件包维护者报告了回归 here。我想它很快就会被修复...

与此同时,您可以尝试从提交之前恢复到 lubridate 的旧版本,或者使用此临时解决方法:

round_date_patched <- function(x, unit) {
  as.Date(round_date(as.POSIXct(x), unit = unit))
}
round_date_patched(x = as.Date("1997-06-29"), unit = "month") # "1997-07-01"