Add a month to a Date [duplicate]

I am trying to add a month to a date i have. But then its not possible in a straight manner so far. Following is what i tried.

d <- as.Date("2004-01-31")
d + 60
# [1] "2004-03-31"

Adding wont help as the month wont be overlapped.

seq(as.Date("2004-01-31"), by = "month", length = 2) 
# [1] "2004-01-31" "2004-03-02"

Above might work , but again its not straight forward. Also its also adding 30 days or something to the date which has issues like the below

seq(as.Date("2004-01-31"), by = "month", length = 10) 
#  [1] "2004-01-31" "2004-03-02" "2004-03-31" "2004-05-01" "2004-05-31" "2004-07-01" "2004-07-31" "2004-08-31" "2004-10-01" "2004-10-31"

In the above , for the first 2 dates , month haven’t changed.

Also the following approach also failed for month but was success for year

d <- as.POSIXlt(as.Date("2010-01-01"))
d$year <- d$year +1
d
# [1] "2011-01-01 UTC"
d <- as.POSIXlt(as.Date("2010-01-01"))
d$month <- d$month +1
d

Error in format.POSIXlt(x, usetz = TRUE) : invalid 'x' argument

What is the right method to do this ?


Function %m+% from lubridate adds one month without exceeding last day of the new month.

library(lubridate)
(d <- ymd("2012-01-31"))
 1 parsed with %Y-%m-%d
[1] "2012-01-31 UTC"
d %m+% months(1)
[1] "2012-02-29 UTC"

It is ambiguous when you say "add a month to a date".

Do you mean

  1. add 30 days?
  2. increase the month part of the date by 1?

In both cases a whole package for a simple addition seems a bit exaggerated.

For the first point, of course, the simple + operator will do:

d=as.Date('2010-01-01') 
d + 30 
#[1] "2010-01-31"

As for the second I would just create a one line function as simple as that (and with a more general scope):

add.months= function(date,n) seq(date, by = paste (n, "months"), length = 2)[2]

You can use it with arbitrary months, including negative:

add.months(d, 3)
#[1] "2010-04-01"
add.months(d, -3)
#[1] "2009-10-01"

Of course, if you want to add only and often a single month:

add.month=function(date) add.months(date,1)
add.month(d)
#[1] "2010-02-01"

If you add one month to 31 of January, since 31th February is meaningless, the best to get the job done is to add the missing 3 days to the following month, March. So correctly:

add.month(as.Date("2010-01-31"))
#[1] "2010-03-03"

In case, for some very special reason, you need to put a ceiling to the last available day of the month, it's a bit longer:

add.months.ceil=function (date, n){

  #no ceiling
  nC=add.months(date, n)

  #ceiling
  day(date)=01
  C=add.months(date, n+1)-1

  #use ceiling in case of overlapping
  if(nC>C) return(C)
  return(nC)
}

As usual you could add a single month version:

add.month.ceil=function(date) add.months.ceil(date,1)    

So:

  d=as.Date('2010-01-31')
  add.month.ceil(d)
  #[1] "2010-02-28"
  d=as.Date('2010-01-21')
  add.month.ceil(d)
  #[1] "2010-02-21"

And with decrements:

  d=as.Date('2010-03-31')
  add.months.ceil(d, -1)
  #[1] "2010-02-28"
  d=as.Date('2010-03-21')
  add.months.ceil(d, -1)
  #[1] "2010-02-21"

Besides you didn't tell if you were interested to a scalar or vector solution. As for the latter:

add.months.v= function(date,n) as.Date(sapply(date, add.months, n), origin="1970-01-01")

Note: *apply family destroys the class data, that's why it has to be rebuilt. The vector version brings:

d=c(as.Date('2010/01/01'), as.Date('2010/01/31'))
add.months.v(d,1)
[1] "2010-02-01" "2010-03-03"

Hope you liked it))


Vanilla R has a naive difftime class, but the Lubridate CRAN package lets you do what you ask:

require(lubridate)
d <- ymd(as.Date('2004-01-01')) %m+% months(1)
d
[1] "2004-02-01"

Hope that helps.