每月日期的序列,以确保它是同一天,或者在无效的情况下是每月的最后一天

喜欢编程

给定一个初始日期,我想生成一个按月间隔的日期序列,以确保每个元素都具有与初始日期相同的日期或月份的最后一天,以防万一同一天产生无效的日期。

听起来很标准,对吧?

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"

因此,假设初始日期在第31天,则将在2月,4月等产生无效日期。因此,该序列实际上会跳过那些月份,因为它“向前计数”并以3月2日结束,而不是2月29日。

如果我从2000年1月31日开始,我希望序列如下:

  • 2000-01-31
  • 2000-02- 29
  • 2000-03-31
  • 2000-04-30
  • ...

并且应该正确处理leap年,因此,如果初始日期为2015-01-31,则顺序应为:

  • 2015-01-31
  • 2015-02- 28
  • 2015-03-31
  • 2015-04-30
  • ...

这些仅是说明问题的示例,我不知道提前的开始日期,我也不能对此做出任何假设。初始日期很可能在当月中旬(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])

它可以工作,但同时又有点笨拙,hacky和令人费解。所以我不喜欢它。最重要的是,我无法相信R中没有比这更简单的方法了。

有人可以给我指出一个更简单的解决方案吗?(我想它应该和一样简单seq(initial_date, "month", 4),但显然并非如此)。我已经用谷歌搜索并在SO和R邮件列表中查看了,但是除了上面提到的技巧外,我找不到解决方案。

瑟图纳

最简单的解决方案是来自lubridate的%m +%,它解决了这个确切的问题。所以:

seq_monthly <- function(from,length.out) {
  return(from %m+% months(c(0:(length.out-1))))
}

输出:

> seq_monthly(as.Date("2015-01-31"),length.out=4)
[1] "2015-01-31" "2015-02-28" "2015-03-31" "2015-04-30"

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章