两个日期之间的月数
Posted
技术标签:
【中文标题】两个日期之间的月数【英文标题】:Number of months between two dates 【发布时间】:2011-01-01 01:01:06 【问题描述】:是否有标准/通用方法/公式来计算 R 中?
我正在寻找类似于MathWorks months function的东西
【问题讨论】:
另见:***.com/a/19687995/59087 【参考方案1】:我正要说这很简单,但difftime()
停在几周后。多么奇怪。
所以一个可能的答案是破解一些东西:
# 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>
似乎是对的。可以将其包装成一些简单的类结构。或将其保留为 hack :)
编辑: 似乎也适用于 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>
添加EndOfMonth
标志留给读者作为练习:)
编辑 2:也许 difftime
将其省略,因为没有可靠的方法来表示与其他单位的 difftime
行为一致的分数差异。
【讨论】:
谢谢,德克。这是一个聪明的把戏。说到单位,我发现这也有效.. >as.numeric(as.Date('2009-10-1') - as.Date('2009-8-01'), units = 'weeks') > as.numeric(as.Date('2009-10-1') - as.Date('2009-8-01'), units = 'days') 但它也停在“weeks”。 我认为这只是巧妙地重载 - 运算符来调用相同的difftime()
函数。俗话说“没有免费的午餐”:)
我发现这对于大型数据集来说非常慢。下面 Manoel Galdino 的答案要快得多。
@anotherfred 并且可能是错误的。快速示例是日期 2017-01-31 和 2018-03-01。在他的第一个答案中给出“13”(一旦我们添加了缺少的as.numeric()
,在第二个答案中添加了“12”。我的答案是“14”。
@DirkEddelbuettel 抱歉,应该澄清一下 - 我的意思是他的第一种方法对于像我这样的情况很有用,我有一个大数据集但所有日期都是本月的 1 日。【参考方案2】:
我认为这是对与 MathWorks 函数奇偶校验问题的更接近的答案
MathWorks 月份函数
MyMonths = months(StartDate, EndDate, EndMonthFlag)
我的 R 代码
library(lubridate)
interval(mdy(10012015), today()) %/% months(1)
输出(与 2016 年 4 月运行代码时一样)
[1] 6
Lubridate [package] 提供的工具可以更轻松地解析和操作日期。这些工具按共同目的分组如下。有关每个函数的更多信息,请参见其帮助文档。
interval lubridate 创建具有指定开始和结束日期的 Interval 类对象。如果开始日期早于结束日期,则间隔将为正数。否则为负数
今天 lubridate 当前日期
months Base 提取月份 这些是通用函数:内部日期时间类的方法记录在这里。
%/% base 表示整数除法 AKA ( x %/% y )(最多舍入误差)
【讨论】:
这对我有用,而其他一些没有。 这对我也有效,而其他人则没有。我不得不将我的结果与 SPSS 中的 datediff 函数进行比较。这与这些结果相符。【参考方案3】:一个简单的函数...
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)
示例...
>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
对我来说,将这个问题简单地考虑为两个日期相减是有意义的,并且由于minuend − subtrahend = difference
(wikipedia),我将较晚的日期放在参数列表的首位。
请注意,尽管这些日期的内部表示年份为负数,但由于减去负数的规则,它对于 1900 年之前的日期工作正常...
> elapsed_months("1791-01-10", "1776-07-01")
[1] 174
【讨论】:
【参考方案4】:可能有更简单的方法。它不是一个函数,但它只有一行。
length(seq(from=date1, to=date2, by='month')) - 1
例如
> length(seq(from=Sys.Date(), to=as.Date("2020-12-31"), by='month')) - 1
生产:
[1] 69
这会计算两个日期之间的整月数。如果您想包含当前月份/不是整月的剩余部分,请删除 -1。
【讨论】:
这并不总是给出预期的结果。length(seq(from=as.Date("2015-01-31"), to=as.Date("2015-03-31"), by='month')) = 3
还有,length(seq(from=as.Date("2015-01-31"), to=as.Date("2015-04-30"), by='month')) = 3
上面的代码现在返回一个错误,因为 Sys.Date()>"2020-12-31" 现在。如果您更改 'from' 和 'to' 参数,它仍然有效。【参考方案5】:
在 R-Help 邮件列表中有一条和你一样的消息(之前我提到了一个 CRAN 列表)。
这里the link。有两种建议的解决方案:
每月平均有 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))
seq.Dates
的长度:
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】:library(lubridate)
case1:朴素函数
mos<-function (begin, end)
mos1<-as.period(interval(ymd(begin),ymd(end)))
mos<-mos1@year*12+mos1@month
mos
案例2:如果您只需要考虑“月”而不考虑“日”
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
例子:
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
【讨论】:
interval(mdy(20150101), mdy(20150228)) %/% months(1) 使用lubridate的原生函数interval即可。 谢谢你。但是,在我的业务中,我需要经常计算 2 天的“月数”。例如,20150131 和 20150201 之间的月份必须为 1。所以,我曾经制作“mob”用户定义函数。你知道怎么用 lubridate 来做这个吗? 我认为您可以使用月份(ymd)-月份(ymd)。或者您可以将年、月和日设为三列。 可以,但是如果是不同的年份,就不行了。例如,月(ymd(20170101)) - 月(ymd(20161231)) = -11 不是 1【参考方案7】: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)
月差 = 12 * 年差 + 月差。
以下可能需要使用
ifelse
条件进行更正 月份减法
【讨论】:
可能值得注意的是,这会导致负数 - 所以要么更改 date1/date2 要么使用abs(etc)
。我认为这是获得几个月的guestimate
的一个非常简单直接的解决方案【参考方案8】:
对我来说这是有效的:
library(lubridate)
Pagos$Datediff <- (interval((Pagos$Inicio_FechaAlta), (Pagos$Inicio_CobFecha)) %/% months(1))
输出是两个日期之间的月数,并存储在 Pagos 数据框的列中。
【讨论】:
感谢您的贡献,但这并没有给出任何小数位。有什么建议吗? 恐怕这只给你几个月的数量。但不能用逗号。我的观点是,应该以天数计算,而不是那样。对于您的情况,我可能会更准确。【参考方案9】:您可以使用 zoo 包中的 as.yearmon() 函数。此函数将日期类型变量转换为年月类型变量。您可以减去两个年月类型变量,然后乘以 12 以获得月份的差异,如下所示:
12 * (as.yearmon(Date1) - as.yearmon(Date2))
【讨论】:
通常不鼓励仅使用代码回答。您能否解释一下为什么它有效或为什么它比其他解决方案更好? @Jason 刚刚做了! 这可行,但as.yearmon()
是zoo
包的一部分,而不是R 基础的一部分。如果你安装了 zoo:12 * (zoo::as.yearmon(Date1) - zoo::as.yearmon(Date2))
【参考方案10】:
以月为单位的日期差异
$date1 = '2017-01-20';
$date2 = '2019-01-20';
$ts1 = strtotime($date1);
$ts2 = strtotime($date2);
$year1 = date('Y', $ts1);
$year2 = date('Y', $ts2);
$month1 = date('m', $ts1);
$month2 = date('m', $ts2);
echo $joining_months = (($year2 - $year1) * 12) + ($month2 - $month1);
【讨论】:
【参考方案11】:另一种简短而方便的方法是:
day1 <- as.Date('1991/04/12')
day2 <- as.Date('2019/06/10')
round(as.numeric(day2 - day1)/30.42)
[1] 338
【讨论】:
以上是关于两个日期之间的月数的主要内容,如果未能解决你的问题,请参考以下文章