给定一个初始日期,我想生成一个月度间隔的日期序列,确保每个元素与初始日期或月份的最后一天具有相同的日期,以防同一天产生无效日期.
听起来很标准,对吧?
使用difftime是不可能的.这是帮助文件的difftime说法:
诸如"月"之类的单位是不可能的,因为它们不是恒定的长度.要创建月,季度或年的间隔,请使用seq.Date或seq.POSIXt.
但随后查看seq.POSIXt我的帮助文件,发现:
使用"月份"首先提前一个月而不更改日期:如果这导致该月的无效日期,则向前计入下个月:请参阅示例.
这是帮助文件中的示例.
seq(ISOdate(2000,1,31), by = "month", length.out = 4)
> seq(ISOdate(2000,1,31), by = "month", length.out = 4)
[1] "2000-01-31 12:00:00 GMT" "2000-03-02 12:00:00 GMT"
"2000-03-31 12:00:00 GMT" "2000-05-01 12:00:00 GMT"
Run Code Online (Sandbox Code Playgroud)
因此,鉴于初始日期是在第31天,这将在2月,4月等产生无效日期.因此,序列最终实际上跳过那些月份,因为它"向前计数"并最终在3月02日结束,而不是二月-29.
如果我从2000-01-31开始,我希望序列如下:
它应该正确处理闰年,所以如果初始日期是2015-01-31,那么序列应该是:
这些只是用来说明问题的例子,我不提前知道初始日期,也不能假设它.初始日期可能在月中(2015-01-15),在这种情况下seq工作正常.但是,正如在示例中那样,在月末使用seq单独使用会产生问题(第29,30和31天)也是如此.我不能假设初始日期是该月的最后一天.
我环顾四周试图寻找解决方案.在SO中的一些问题中(例如这里)有一个"技巧"来获得一个月的最后一天,通过获取下个月的第一天并简单地减去1.并且找到第一天是"容易的",因为它就在第一天.
所以到目前为止我的解决方案是
# Given an initial date for my sequence
initial_date <- as.Date("2015-01-31")
# Find the first day of the month
library(magrittr) # to use pipes and make the code more readable
firs_day_of_month <- initial_date %>%
format("%Y-%m") %>%
paste0("-01") %>%
as.Date()
# Generate a sequence from initial date, using seq
# This is the sequence that will have incorrect values in months that would
# have invalid dates
given_dat_seq <- seq(initial_date, by = "month", length.out = 4)
# And then generate an auxiliary sequence for the last day of the month
# I do this generating a sequence that starts the first day of the
# same month as initial date and it goes one month further
# (lenght 5 instead of 4) and substract 1 to all the elements
last_day_seq <- seq(firs_day_of_month, by = "month", length.out = 5)-1
# And finally, for each pair of elements, I take the min date of both
pmin(given_dat_seq, last_day_seq[2:5])
Run Code Online (Sandbox Code Playgroud)
它有效,但同时又有点愚蠢,愚蠢和错综复杂.所以我不喜欢它.最重要的是,我无法相信在R中没有更简单的方法可以做到这一点.
有人可以指点我一个更简单的解决方案吗?(我想它应该一样简单seq(initial_date, "month", 4),但显然不是).我用Google搜索并在SO和R邮件列表中查看,但除了我上面提到的技巧之外,我找不到解决方案.
最简单的解决方案是来自lubridate的%m +%,这解决了这个确切的问题.所以:
seq_monthly <- function(from,length.out) {
return(from %m+% months(c(0:(length.out-1))))
}
Run Code Online (Sandbox Code Playgroud)
输出:
> seq_monthly(as.Date("2015-01-31"),length.out=4)
[1] "2015-01-31" "2015-02-28" "2015-03-31" "2015-04-30"
Run Code Online (Sandbox Code Playgroud)