1

I am trying to write a function that, given a date start and an integer n, adds n months to the date and then takes the last day of the resulting month. The following piece of code, however, returns NA for n=8+12k, but seems to work in other cases.

library(lubridate)
start <- ymd("2020-06-29")
n <- 8
floor_date(start + months(n), "month") + months(1) - days(1)
>[1] NA

I guess this is somewhat due to the existence of leap years, but I still find it puzzling. Plus, I couldn't find anything in the docs about this.

Can someone please explain what is going on, or suggest a better way to do the job?

Alessandro
  • 161
  • 5
  • 1
    This is probably because you're hitting February with the `floor_date()` statement and there with only 28 days, `lubridate` gives an NA when you ask for the 29th – Tech Commodities Sep 08 '21 at 16:56
  • Try this instead, `add_with_rollback(start, months(n)) + months(1) - days(3)` – Tech Commodities Sep 08 '21 at 16:59
  • 1
    Try `%m+%`, "Add [...] months to a date without exceeding the last day of the new month", as described e.g. here: [Add/subtract 6 months (bond time) in R using lubridate](https://stackoverflow.com/questions/22628863/add-subtract-6-months-bond-time-in-r-using-lubridate/22646010#22646010) – Henrik Sep 08 '21 at 17:22
  • Thanks @Henrik! I couldn't find that answer – Alessandro Sep 09 '21 at 07:24

1 Answers1

1

The clock package is really good for this, as it has an explicit argument specifying what you want done with invalid dates. And also the date_end function.
I think you want: (R >= 4.1 for native pipe)

library(clock)
start <- parse_date("2020-06-29")
n <- 8
start |> add_months(n, invalid = "previous") |> date_end('month')

Which gives: [1] "2021-02-28"

Brian Montgomery
  • 2,244
  • 5
  • 15