Number of months between two dates

2019-01-02 20:34发布

Is there a standard/common method/formula to calculate the number of months between two dates in R?

I am looking for something that is similar to MathWorks months function

标签: r date
7条回答
爱死公子算了
2楼-- · 2019-01-02 21:06
library(lubridate)

case1: naive function

mos<-function (begin, end) {
      mos1<-as.period(interval(ymd(begin),ymd(end)))
      mos<-mos1@year*12+mos1@month
      mos
}

case2: if you need to consider only 'Month' regardless of 'Day'

mob<-function (begin, end) {
      begin<-paste(substr(begin,1,6),"01",sep="")
      end<-paste(substr(end,1,6),"01",sep="")
      mob1<-as.period(interval(ymd(begin),ymd(end)))
      mob<-mob1@year*12+mob1@month
      mob
}

Example :

mos(20150101,20150228) # 1
mos(20150131,20150228) # 0
# you can use "20150101" instead of 20150101

mob(20150131,20150228) # 1
mob(20150131,20150228) # 1
# you can use a format of "20150101", 20150101, 201501
查看更多
梦寄多情
3楼-- · 2019-01-02 21:08

There may be a simpler way. It's not a function but it is only one line.

length(seq(from=date1, to=date2, by='month')) - 1

e.g.

> length(seq(from=Sys.Date(), to=as.Date("2020-12-31"), by='month')) - 1

Produces:

[1] 69

This calculates the number of whole months between the two dates. Remove the -1 if you want to include the current month/ remainder that isn't a whole month.

查看更多
余欢
4楼-- · 2019-01-02 21:09

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)

查看更多
爱死公子算了
5楼-- · 2019-01-02 21:11

There is a message just like yours in the R-Help mailing list (previously I mentioned a CRAN list).

Here the link. There are two suggested solutions:

  • There are an average of 365.25/12 days per month so the following expression gives the number of months between d1 and d2:
#test data 
d1 <- as.Date("01 March 1950", "%d %B %Y")    
d2 <- as.Date(c("01 April 1955", "01 July 1980"), "%d %B %Y")
# calculation 
round((d2 - d1)/(365.25/12))
  • Another possibility is to get the length of seq.Dates like this:
as.Date.numeric <- function(x) structure(floor(x+.001), class = "Date")
sapply(d2, function(d2) length(seq(d1, as.Date(d2), by = "month")))-1
查看更多
皆成旧梦
6楼-- · 2019-01-02 21:13
library(lubridate)
date1 = "1 April 1977"
date2 = "7 July 2017"

date1 = dmy(date1)
date2 = dmy(date2)
number_of_months = (year(date1) - year(date2)) * 12 + month(date1) - month(date2)

Difference in months = 12 * difference in years + difference in months.

Following may need to be corrected using ifelse condition for the month subtractions

查看更多
像晚风撩人
7楼-- · 2019-01-02 21:27

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.

查看更多
登录 后发表回答