Number of months between two dates

Solution 1:

I was about to say that's simple, but difftime() stops at weeks. How odd.

So one possible answer would be to hack something up:

# turn a date into a 'monthnumber' relative to an origin
R> monnb <- function(d) { lt <- as.POSIXlt(as.Date(d, origin="1900-01-01")); \
                          lt$year*12 + lt$mon } 
# compute a month difference as a difference between two monnb's
R> mondf <- function(d1, d2) { monnb(d2) - monnb(d1) }
# take it for a spin
R> mondf(as.Date("2008-01-01"), Sys.Date())
[1] 24
R> 

Seems about right. One could wrap this into some simple class structure. Or leave it as a hack :)

Edit: Also seems to work with your examples from the Mathworks:

R> mondf("2000-05-31", "2000-06-30")
[1] 1
R> mondf(c("2002-03-31", "2002-04-30", "2002-05-31"), "2002-06-30")
[1] 3 2 1
R> 

Adding the EndOfMonth flag is left as an exercise to the reader :)

Edit 2: Maybe difftime leaves it out as there is no reliable way to express fractional difference which would be consistent with the difftime behavior for other units.

Solution 2:

I think this is a closer answer to the question asked in terms of parity with MathWorks function

MathWorks months function

MyMonths = months(StartDate, EndDate, EndMonthFlag)

My R code

library(lubridate)
interval(mdy(10012015), today()) %/% months(1)

Output (as when the code was run in April 2016)

[1] 6

Lubridate [package] provides tools that make it easier to parse and manipulate dates. These tools are grouped below by common purpose. More information about each function can be found in its help documentation.

interval {lubridate} creates an Interval-class object with the specified start and end dates. If the start date occurs before the end date, the interval will be positive. Otherwise, it will be negative

today {lubridate} The current date

months {Base} Extract the month These are generic functions: the methods for the internal date-time classes are documented here.

%/% {base} indicates integer division AKA ( x %/% y ) (up to rounding error)

Solution 3:

A simple function...

elapsed_months <- function(end_date, start_date) {
    ed <- as.POSIXlt(end_date)
    sd <- as.POSIXlt(start_date)
    12 * (ed$year - sd$year) + (ed$mon - sd$mon)
}

Example...

>Sys.time()
[1] "2014-10-29 15:45:44 CDT"
>elapsed_months(Sys.time(), as.Date("2012-07-15"))
[1] 27
>elapsed_months("2002-06-30", c("2002-03-31", "2002-04-30", "2002-05-31"))
[1] 3 2 1

To me it makes sense to think about this problem as simply subtracting two dates, and since minuend − subtrahend = difference (wikipedia), I put the later date first in the parameter list.

Note that it works fine for dates preceeding 1900 despite those dates having internal representations of year as negative, thanks to the rules for subtracting negative numbers...

> elapsed_months("1791-01-10", "1776-07-01")
[1] 174