81 votes

Nombre de mois entre deux dates

Existe-t-il une méthode/formule standard/commune pour calculer le nombre de mois entre deux dates dans R ?

Je cherche quelque chose qui soit similaire à Fonction mois de MathWorks

72voto

Dirk Eddelbuettel Points 134700

J'étais sur le point de dire que c'est simple, mais difftime() s'arrête aux semaines. Comme c'est étrange.

Une réponse possible serait donc de pirater quelque chose :

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

Ça semble correct. On pourrait intégrer cela dans une structure de classe simple. Ou le laisser comme un hack :)

Edit : Cela semble également fonctionner avec vos exemples des 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> 

Ajout de la EndOfMonth Le drapeau est laissé à l'exercice du lecteur :)

Edit 2 : Peut-être difftime le laisse de côté car il n'y a pas de moyen fiable d'exprimer une différence fractionnelle qui serait cohérente avec l'approche de l'UE. difftime comportement pour les autres unités.

58voto

mtelesha Points 31

Je pense que c'est une réponse plus proche de la question posée en termes de parité avec la fonction MathWorks.

Fonction mois de MathWorks

MyMonths = months(StartDate, EndDate, EndMonthFlag)

Mon code R

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

Résultat (comme lorsque le code a été exécuté en avril 2016)

[1] 6

Lubridate [paquet] fournit des outils qui facilitent l'analyse et la manipulation des dates. Ces outils sont regroupés ci-dessous par objectif commun. Vous trouverez de plus amples informations sur chaque fonction dans sa documentation d'aide.

intervalle {lubridate} crée un objet de classe Intervalle avec les dates de début et de fin spécifiées. Si la date de début est antérieure à la date de fin, l'intervalle sera positif. Sinon, il sera négatif.

aujourd'hui {lubridate} La date actuelle

mois {Base} Extraire le mois Il s'agit de fonctions génériques : les méthodes des classes internes de date-heure sont documentées ici.

%/% {base} indique la division d'un nombre entier alias ( x %/% y ) (jusqu'à l'erreur d'arrondi)

54voto

pbnelson Points 1019

Une simple fonction...

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

Exemple...

>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

Pour moi, il est logique de penser à ce problème comme une simple soustraction de deux dates, et comme minuend subtrahend = difference (wikipedia) Je mets la date la plus récente en premier dans la liste des paramètres.

Notez que cela fonctionne bien pour les dates antérieures à 1900, bien que ces dates aient des représentations internes de l'année en négatif, grâce aux règles de soustraction des nombres négatifs...

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

45voto

Dominic Points 586

Il existe peut-être un moyen plus simple. Ce n'est pas une fonction mais il n'y a qu'une ligne.

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

par exemple

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

Produit :

[1] 69

Cela calcule le nombre de mois entiers entre les deux dates. Enlevez le -1 si vous voulez inclure le mois actuel/le reste qui n'est pas un mois entier.

14voto

Manoel Galdino Points 713

Il y a un message exactement comme le vôtre dans la liste de diffusion R-Help (j'ai mentionné précédemment une liste CRAN).

Ici le lien . Deux solutions sont proposées :

  • Il y a en moyenne 365,25/12 jours par mois, l'expression suivante donne donc le nombre de mois entre d1 et 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))
  • Une autre possibilité est d'obtenir la longueur de seq.Dates comme ça :
as.Date.numeric <- function(x) structure(floor(x+.001), class = "Date")
sapply(d2, function(d2) length(seq(d1, as.Date(d2), by = "month")))-1

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X