Количество месяцев между двумя датами

Существует ли стандартный / общий метод / формула для расчета количества месяцев между двумя датами в R?

Я ищу что-то похожее на функцию месяцев MathWorks

Я собирался сказать, что это просто, но 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> 

Кажется, правильно. Можно было бы превратить это в некоторую простую структуру classов. Или оставьте это как хак 🙂

Редактировать: также, похоже, работает с вашими примерами из 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 поведению для других единиц.

Простая функция …

 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 

Может быть, проще. Это не функция, а только одна строка.

 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, если вы хотите включить текущий месяц / остаток, который не является целым месяцем.

Я думаю, что это более близкий ответ на вопрос, заданный с точки зрения паритета с функцией MathWorks

Функция месяцев MathWorks

 MyMonths = months(StartDate, EndDate, EndMonthFlag) 

Мой код R

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

Выход (как при запуске кода в апреле 2016 года)

 [1] 6 

Lubridate [package] предоставляет инструменты, облегчающие анализ и обработку дат. Эти инструменты сгруппированы по общей цели. Более подробную информацию о каждой функции можно найти в ее справочной документации.

interval {lubridate} создает объект Interval-class с указанными датами начала и окончания. Если дата начала происходит до даты окончания, интервал будет положительным. В противном случае это будет отрицательным

сегодня {lubridate} Текущая дата

месяцев {База} Извлечение месяца. Это общие функции: здесь описаны методы для внутренних classов времени.

% /% {base} указывает целочисленное деление AKA (x% /% y) (с точностью до округления)

В списке рассылки R-Help есть сообщение, подобное вашему, (ранее я упоминал список CRAN).

Вот ссылка . Существует два предложенных решения:

  • В среднем в среднем 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 
 library(lubridate) 

case1: наивная функция

 mos<-function (begin, end) { mos1<-as.period(interval(ymd(begin),ymd(end))) mos<[email protected]*[email protected] mos } 

case2: если вам нужно рассматривать только «Месяц» независимо от «Дня»,

 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<[email protected]*[email protected] 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 
 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 для вычитания месяца

Давайте будем гением компьютера.