两个日期之间的月数。

时间:2021-09-01 12:07:13

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

是否有一个标准/通用的方法/公式来计算R中两个日期之间的月数?

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

我正在寻找类似于MathWorks月功能的东西。

7 个解决方案

#1


40  

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:

编辑:似乎也与你的例子从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.

编辑2:由于没有可靠的方法来表达分数差,这与其他单位的扩散行为是一致的,所以可能会把它排除在外。

#2


33  

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...

值得注意的是,在1900年之前,它的运行良好,尽管那些年的内部表现为负数,这要感谢那些减少负数的规则……

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

#3


28  

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.

这可以计算两个日期之间的整个月份。如果你想要包含当月/其余月份,请删除-1。

#4


16  

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

我认为这是与MathWorks函数等价的一个更接近的答案。

MathWorks months function

MathWorks月功能

MyMonths = months(StartDate, EndDate, EndMonthFlag)

My R code

我的R代码

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

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

输出(当代码在2016年4月运行时)

[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.

Lubridate [package]提供了一些工具,可以更容易地解析和操作日期。这些工具按共同的目的分组。关于每个函数的更多信息可以在它的帮助文档中找到。

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

interval {lubridate}创建一个具有指定的起始日期和结束日期的intervalclass对象。如果开始日期发生在结束日期之前,那么间隔将是正的。否则,它将是负的。

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)

%/%{基础}表示整数分区AKA (x %/% y)(向上到舍入误差)

#5


5  

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

在R-Help邮件列表中有一个类似于您的消息(之前我提到过一个CRAN列表)。

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:
  • 每个月平均有365.25/12天,因此下面的表达式给出了d1和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:
  • 另一种可能是得到seq的长度。日期:
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


5  

library(lubridate)

case1: naive function

case1:天真的函数

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'

case2:如果你只考虑“月”,而不考虑“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

#7


3  

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.

月差= 12 *年差+月差。

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

以下可能需要更正,使用ifelse条件进行减法。

#1


40  

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:

编辑:似乎也与你的例子从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.

编辑2:由于没有可靠的方法来表达分数差,这与其他单位的扩散行为是一致的,所以可能会把它排除在外。

#2


33  

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...

值得注意的是,在1900年之前,它的运行良好,尽管那些年的内部表现为负数,这要感谢那些减少负数的规则……

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

#3


28  

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.

这可以计算两个日期之间的整个月份。如果你想要包含当月/其余月份,请删除-1。

#4


16  

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

我认为这是与MathWorks函数等价的一个更接近的答案。

MathWorks months function

MathWorks月功能

MyMonths = months(StartDate, EndDate, EndMonthFlag)

My R code

我的R代码

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

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

输出(当代码在2016年4月运行时)

[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.

Lubridate [package]提供了一些工具,可以更容易地解析和操作日期。这些工具按共同的目的分组。关于每个函数的更多信息可以在它的帮助文档中找到。

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

interval {lubridate}创建一个具有指定的起始日期和结束日期的intervalclass对象。如果开始日期发生在结束日期之前,那么间隔将是正的。否则,它将是负的。

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)

%/%{基础}表示整数分区AKA (x %/% y)(向上到舍入误差)

#5


5  

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

在R-Help邮件列表中有一个类似于您的消息(之前我提到过一个CRAN列表)。

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:
  • 每个月平均有365.25/12天,因此下面的表达式给出了d1和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:
  • 另一种可能是得到seq的长度。日期:
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


5  

library(lubridate)

case1: naive function

case1:天真的函数

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'

case2:如果你只考虑“月”,而不考虑“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

#7


3  

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.

月差= 12 *年差+月差。

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

以下可能需要更正,使用ifelse条件进行减法。