提问人:Algebro1000 提问时间:1/10/2023 更新时间:1/10/2023 访问量:69
R 中日期的定制地板/天花板
Customized floor/ceiling for dates in R
问:
假设我有一个从到哪里的日期范围。start
end
start <- as.Date(2009-11-05), end <- as.Date(2009-12-17)
我想要一个函数,它本质上充当自定义的地板/天花板并返回一个日期间隔,使下限是形式“yyyy-mm-23”的第一个日期,小于或等于“2009-11-05”,上限是第一个大于或等于“2009-12-17”且格式为“yyyy-mm-22”的日期。
在上面的示例中,该函数应返回间隔 ('2009-10-23, 2009-12-22)。
我试过使用 seq。日期并在其上使用长度功能,但这似乎很乏味,我想知道是否有更快的解决方案。
谢谢
答:
2赞
Vinícius Félix
1/10/2023
#1
我不知道有这样的函数,但我会编写如下代码:
法典
custom_bound <- function(date, type, ref_day){
obs_day <- lubridate::day(date)
if(type == "lower"){aux <- -1}
if(type == "upper"){aux <- 1}
while(obs_day != ref_day ){
date <- date + days(aux)
obs_day <- lubridate::day(date)
}
return(date)
}
输出
> custom_bound(date = as.Date("2009-11-05"),type = "lower",ref_day = 23)
[1] "2009-10-23"
> custom_bound(date = as.Date("2009-12-17"),type = "upper",ref_day = 22)
[1] "2009-12-22"
1赞
Ben
1/10/2023
#2
这可能是另一种尝试的方法。使用创建新的开始日期和结束日期,替换 23 日和 22 日。然后,如果开始日期早于 23 日,则减去一个月。同样,如果结束日期超过 22 日,则增加一个月。lubridate
start <- as.Date("2009-11-05")
end <- as.Date("2009-12-17")
library(lubridate)
my_fun <- function(start, end) {
new_start <- start
day(new_start) <- 23
new_end <- end
day(new_end) <- 22
if (day(start) < 23) new_start = new_start %m-% months(1)
if (day(end) > 22) new_end = new_end %m+% months(1)
return(interval(new_start, new_end))
}
my_fun(start, end)
输出
[1] 2009-10-23 UTC--2009-12-22 UTC
编辑:在评论中,该月的参考日期可能大于 28,这可能导致日期无效。要考虑这种可能性,一种方法是使用可以处理无效日期(例如,2 月 31 日)的包,然后解析为最接近的日期。clock
start <- as.Date("2009-03-30")
end <- as.Date("2009-12-17")
reference <- 31
library(lubridate)
library(clock)
my_fun <- function(start, end, reference) {
new_start <- set_day(year_month_day(year(start), month(start)), reference)
new_end <- set_day(year_month_day(year(end), month(end)), reference)
if (day(start) < reference) new_start = add_months(new_start, -1)
if (day(end) > reference) new_end = add_months(new_end, 1)
new_start = invalid_resolve(new_start, invalid = "previous")
new_end = invalid_resolve(new_end, invalid = "next")
return(c(new_start, new_end))
}
my_fun(start, end, reference)
输出
[1] "2009-02-28" "2009-12-31"
评论
0赞
Algebro1000
1/10/2023
谢谢,这正是我想要的!漂亮而简单,避免了使用 seq 创建日期序列。日期
0赞
Algebro1000
1/10/2023
如果我们以 31 日为参考日,开始日期是 2009-02-28,该怎么办?我们当然不能设置 day(new_start) <- 31,但我们希望new_start是 2009-02-28?
0赞
Ben
1/10/2023
@Lollo231000 如果可以有一个大于 28 的“参考”日期,则可以使用该包,然后解析无效日期。请参阅上面编辑的答案中的第二个示例。让我知道这是否是你的想法。clock
1赞
Algebro1000
1/11/2023
多么精彩的套餐!非常感谢您的出色解决方案。
评论