Numero di mesi tra due date

Esiste un metodo / formula standard / comune per calcolare il numero di mesi tra due date in R?

Sto cercando qualcosa che sia simile alla funzione di mesi di MathWorks

Stavo per dire che è semplice, ma difftime() ferma a settimane. Che strano.

Quindi una ansible risposta sarebbe quella di hackerare qualcosa:

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

Sembra giusto. Uno potrebbe avvolgere questo in una semplice struttura di class. O lascialo come un trucco 🙂

Modifica: sembra funzionare anche con i tuoi esempi da 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> 

L’aggiunta del flag EndOfMonth viene lasciata come esercizio al lettore 🙂

Modifica 2: Forse difftime lascia fuori perché non esiste un modo affidabile per esprimere la differenza frazionaria che sarebbe coerente con il comportamento difftime per le altre unità.

Una semplice funzione …

 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) } 

Esempio...

 >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 

Per me ha senso pensare a questo problema come semplicemente sottraendo due date, e poiché minuend − subtrahend = difference (wikipedia) , inserisco la data successiva prima nell'elenco dei parametri.

Si noti che funziona bene per date precedenti al 1900, nonostante quelle date con rappresentazioni interne dell'anno come negative, grazie alle regole per sottrarre numeri negativi ...

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

Potrebbe esserci un modo più semplice. Non è una funzione ma è solo una riga.

 length(seq(from=date1, to=date2, by='month')) - 1 

per esempio

 > length(seq(from=Sys.Date(), to=as.Date("2020-12-31"), by='month')) - 1 

produce:

 [1] 69 

Questo calcola il numero di mesi interi tra le due date. Rimuovi il -1 se desideri includere il mese / resto corrente che non è un mese intero.

Penso che questa sia una risposta più vicina alla domanda posta in termini di parità con la funzione MathWorks

Funzione MathWorks months

 MyMonths = months(StartDate, EndDate, EndMonthFlag) 

Il mio codice R

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

Output (come quando il codice è stato eseguito ad aprile 2016)

 [1] 6 

Lubridate [pacchetto] fornisce strumenti che semplificano l’analisi e la manipolazione delle date. Questi strumenti sono raggruppati sotto per uno scopo comune. Ulteriori informazioni su ciascuna funzione sono disponibili nella documentazione della guida.

interval {lubridate} crea un object di class Interval con le date di inizio e di fine specificate. Se la data di inizio si verifica prima della data di fine, l’intervallo sarà positivo. Altrimenti, sarà negativo

oggi {lubridate} La data corrente

mesi {Base} Estrai il mese Queste sono funzioni generiche: qui sono documentati i metodi per le classi interne di data-ora.

% /% {base} indica la divisione intera AKA (x% /% y) (fino all’arrotondamento)

C’è un messaggio proprio come il tuo nella mailing list di R-Help (in precedenza ho menzionato un elenco CRAN).

Qui il link . Ci sono due soluzioni suggerite:

  • Ci sono in media 365.25 / 12 giorni al mese, quindi la seguente espressione indica il numero di mesi tra d1 e 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)) 
  • Un'altra possibilità è quella di ottenere la lunghezza di seq.Dates come questo:
 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) 

caso1: funzione ingenua

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

caso2: se è necessario considerare solo 'Mese' indipendentemente dal 'Giorno'

 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 } 

Esempio :

 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) 

Differenza in mesi = 12 * differenza in anni + differenza in mesi.

Potrebbe essere necessario correggere il ifelse utilizzando la condizione ifelse per le sottrazioni del mese