hadley/lubridate — Issue #113: Adding `months` periods to end of month instant badness
Author: mannyishere
Created: 2012-02-24 00:14:43+00:00
State: open

Loving `lubridate`. However, there are a few bugs I've noticed. One of which is the following.

Suppose we have the end of a month instant:
```date3 <- ymd("2012-07-31")```

Now suppose that wewould like to find the instant one (period) month from `date3`:
```date3 + months(1) # "2012-08-31 UTC"```

*This looks right*.

Now suppose that we would like to find the instant two (period) months from `date3`:
```date3 + months(2) # "2012-10-01 UTC"```

*This looks wrong*.

The common behaviour for this sort of operation should be to return the last day of the month when the original date is the 31st of a month. Otherwise it should return the same `mday` for month `N` (period) months from the original date. I've coded the behaviour I would expect here:

```
shiftDateByNMonths <- function (date1, N) {

N <- as.integer(N)

if (is.na(N)) {

stop ("Your N is bigger in modulus than the largest integer. Try again.")

}

year <- year(date1)
month <- month(date1)
day <- mday(date1)

iYear <- year
iMonth <- month + N
iDay <- day

while ((iMonth > 12) | (iMonth <= 0)){
iMonth <- iMonth - sign(N) * 12
iYear <- iYear + sign(N) * 1
}

lastDay <- getDaysInMonth(ymd(paste(iYear, iMonth, 1, sep="-")))

if (iDay > lastDay) {
iDay <- lastDay
}

shiftedDate <- ymd(paste(iYear, iMonth, iDay, sep="-"))

return (shiftedDate)

}
```

This function's test cases (and results) are:
```
> date3 <- ymd("2011-02-28")
> shiftDateByNMonths(date3, 1) # "2011-03-28 UTC"
> date3 <- ymd("2012-02-29")
> shiftDateByNMonths(date3, 1) # "2012-03-29 UTC"
> date3 <- ymd("2012-04-30")
> shiftDateByNMonths(date3, 1) # "2012-05-30 UTC"
> date3 <- ymd("2012-03-31")
> shiftDateByNMonths(date3, 1) # "2012-04-30 UTC"
```

Hope that clarifies what I would expect. Love to hear feedback. Perhaps I misunderstood the definition of a `period` (as per "Dates and Times Made Easy with lubridate", Apr 2011)