Получить разницу дат в годах (с плавающей запятой)

Я хочу исправить исходную активность на основе разницы между датой отсчета и даты измерения и периодом полужизни источника (измеряется в годах). Скажем, у меня

ref_date <- as.Date('06/01/08',format='%d/%m/%y')

и столбец в моем data.frame с тем же самым форматом даты, например,

today <- as.Date(Sys.Date(), format='%d/%m/%y')

Я могу найти количество лет между этими датами, используя пакет lubridate

year(today)-year(ref_date)
[1] 5

Есть ли функция, которую я могу использовать для получения ответа с плавающей запятой today - ref_date= 5.2y, например?

Ответ 1

Да, конечно, используйте difftime() с числовым:

R> as.numeric(difftime(as.Date("2003-04-05"), as.Date("2001-01-01"), 
+                      unit="weeks"))/52.25
[1] 2.2529
R> 

Обратите внимание, что нам нужно переключиться на недели, измененные на 52.25, так как есть немного двусмысленности там с точки зрения подсчета лет --- 29 февраля происходит каждые 4 года, но не каждый 100-й и т.д.

Итак, вы должны это определить. difftime() обрабатывает все единицы времени до нескольких недель. Месяцы не могут быть выполнены по той же причине непостоянного "числителя".

Ответ 2

Пакет lubridate содержит встроенную функцию time_length, которая может помочь выполнить эту задачу.

time_length(difftime(as.Date("2003-04-05"), as.Date("2001-01-01")), "years")
[1] 2.257534

time_length(difftime(as.Date("2017-03-01"), as.Date("2012-03-01")),"years")
[1] 5.00274

Документацию для пакета lubridate можно найти здесь.

Ответ 3

Вдохновленный Брайаном Ф., time_length() будет работать лучше, если использовать объект интервала

time_length(interval(as.Date("2003-04-05"), as.Date("2001-01-01")), "years")
[1] -2.257534
time_length(difftime(as.Date("2017-03-01"), as.Date("2012-03-01")),"years")
[1] 5.00274
time_length(interval(as.Date("2017-03-01"), as.Date("2012-03-01")),"years")
[1] -5

Вы можете увидеть, используете ли вы interval() для получения разницы во времени и затем передаете ее time_length(), time_length() учитывает тот факт, что не все месяцы и годы имеют одинаковое количество дней, например високосный год,

Ответ 4

Неточный ответ на ваш вопрос, но ответ от Dirk Eddelbuettel в некоторых ситуациях может привести к небольшим ошибкам.

Пожалуйста, рассмотрите следующий пример:

as.numeric(difftime(as.Date("2012-03-01"), as.Date("2017-03-01"), unit="weeks"))/52.25
[1] -4.992481

Правильный ответ здесь должен быть не менее 5 лет.

Следующая функция (с использованием пакета lubridate) рассчитает число полных лет между двумя датами:

# Function to calculate an exact full number of years between two dates
year.diff <- function(firstDate, secondDate) {
  yearsdiff <- year(secondDate) - year(firstDate)
  monthsdiff <- month(secondDate) - month(firstDate)
  daysdiff <- day(secondDate) - day(firstDate)

  if ((monthsdiff < 0) | (monthsdiff == 0 & daysdiff < 0)) {
    yearsdiff <- yearsdiff - 1
  }

  yearsdiff
}

Вы можете изменить его, чтобы вычислить дробную часть в зависимости от того, как вы определяете количество дней в последний (не законченный) год.

Ответ 5

Вы можете использовать функцию AnnivDates() пакета BondValuation:

R> library('BondValuation')
R> DateIndexes <- unlist(
+   suppressWarnings(
+     AnnivDates("2001-01-01", "2003-04-05", CpY=1)$DateVectors[2]
+     )
+   )
R> names(DateIndexes) <- NULL
R> DateIndexes[length(DateIndexes)] - DateIndexes[1]
[1] 2.257534

Нажмите здесь для документации пакета BondValuation.

Ответ 6

Поскольку вы уже используете пакет lubridate, вы можете получить количество лет в плавающей запятой, используя простой трюк:

найдите количество секунд в году:

seconds_in_a_year <- as.integer((seconds(ymd("2010-01-01")) - seconds(ymd("2009-01-01"))))

теперь получите количество секунд между двумя желаемыми датами

seconds_between_dates <- as.integer(seconds(date1) - seconds(date2))

ваш окончательный ответ за количество лет в плавающих точках будет

years_between_dates <- seconds_between_dates / seconds_in_a_year