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

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

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

8 ответов

Решение

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

Кажется о праве. Можно было бы обернуть это в некоторую простую структуру класса. Или оставить как взломать:)

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

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

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

MyMonths = months(StartDate, EndDate, EndMonthFlag)

Мой код R

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

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

[1] 6

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

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

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

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

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

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

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 (Википедия), я поставил более позднюю дату в списке параметров.

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

В списке рассылки 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)

Pagos$Datediff <- (interval((Pagos$Inicio_FechaAlta), (Pagos$Inicio_CobFecha)) %/% months(1))

Результатом является количество месяцев между двумя датами, которое хранится в столбце фрейма данных Pagos.

library(lubridate)

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

mos<-function (begin, end) {
      mos1<-as.period(interval(ymd(begin),ymd(end)))
      mos<-mos1@year*12+mos1@month
      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<-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
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 условие для вычитания месяца

Вы можете использовать функцию as.yearmon() из пакета zoo. Эта функция преобразует переменную типа Date в переменную типа год-месяц. Вы можете вычесть две переменные типа год-месяц, а затем умножить их на 12, чтобы получить разницу в месяцах следующим образом:

12 * (as.yearmon(Date1) - as.yearmon(Date2))

Еще один короткий и удобный способ:

day1 <- as.Date('1991/04/12')
day2 <- as.Date('2019/06/10')
round(as.numeric(day2 - day1)/30.42)

[1] 338

Разница дат в месяцах

$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);
Другие вопросы по тегам