Anzahl der Monate zwischen zwei Daten


Antworten:


62

Ich wollte gerade sagen, dass das einfach ist, difftime()hört aber nach Wochen auf. Wie seltsam.

Eine mögliche Antwort wäre also, etwas zu hacken:

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

Scheint ungefähr richtig. Man könnte dies in eine einfache Klassenstruktur einwickeln. Oder lass es als Hack :)

Bearbeiten: Scheint auch mit Ihren Beispielen aus dem Mathworks zu funktionieren:

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> 

Das Hinzufügen der EndOfMonthFlagge bleibt dem Leser als Übung überlassen :)

Bearbeiten 2: Lässt difftimees möglicherweise weg, da es keine zuverlässige Möglichkeit gibt, Bruchdifferenzen auszudrücken, die mit dem difftimeVerhalten für andere Einheiten übereinstimmen würden .


Danke, Dirk. Das ist ein kluger Trick. Apropos Einheiten, ich fand heraus, dass dies auch funktioniert ..> as.numerisch (as.Date ('2009-10-1') - as.Date ('2009-8-01'), Einheiten = 'Wochen') > as.numerisch (as.Date ('2009-10-1') - as.Date ('2009-8-01'), Einheiten = 'Tage'), aber es endet auch bei 'Wochen'.
Knguyen

Ich denke, das ist nur eine clevere Überladung des Operators -, um dieselbe difftime()Funktion aufzurufen . "No Free Lunch" wie das Sprichwort sagt :)
Dirk Eddelbuettel

Ich fand das für große Datenmengen sehr langsam. Die Antwort von Manoel Galdino unten ist viel schneller.
Anotherfred

1
@anotherfred Und möglicherweise falsch. Ein kurzes Beispiel sind die Daten 2017-01-31 und 2018-03-01. Gibt hier '13' mit seiner ersten Antwort (sobald wir die fehlende hinzufügen as.numeric(), und '12' mit der zweiten Antwort. Meine Antwort gibt '14', wie man möchte.
Dirk Eddelbuettel

@DirkEddelbuettel Entschuldigung, hätte klarstellen sollen - ich meinte, seine erste Methode ist nützlich für Fälle wie meinen, in denen ich einen großen Datensatz habe, aber alle Daten der 1. des Monats sind.
Anotherfred

49

Eine einfache Funktion ...

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

Beispiel...

>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

Für mich ist es sinnvoll, dieses Problem als einfaches Subtrahieren von zwei Daten zu betrachten, und da minuend − subtrahend = difference(Wikipedia) habe ich das spätere Datum zuerst in die Parameterliste aufgenommen.

Beachten Sie, dass es für Daten vor 1900 gut funktioniert, obwohl diese Daten interne Darstellungen des Jahres als negativ aufweisen, dank der Regeln zum Subtrahieren negativer Zahlen ...

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

43

Ich denke, dies ist eine genauere Antwort auf die Frage, die in Bezug auf die Parität mit der MathWorks-Funktion gestellt wird

MathWorks Monatsfunktion

MyMonths = months(StartDate, EndDate, EndMonthFlag)

Mein R-Code

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

Ausgabe (als der Code im April 2016 ausgeführt wurde)

[1] 6

Lubridate [Paket] bietet Tools, mit denen Datumsangaben einfacher analysiert und bearbeitet werden können . Diese Tools sind nachstehend nach allgemeinem Zweck zusammengefasst. Weitere Informationen zu den einzelnen Funktionen finden Sie in der Hilfedokumentation.

intervall {lubridate} erstellt ein Intervallklassenobjekt mit den angegebenen Start- und Enddaten . Wenn das Startdatum vor dem Enddatum liegt, ist das Intervall positiv. Andernfalls wird es negativ sein

today {lubridate} Das aktuelle Datum

Monate {Basis} Monat extrahieren Dies sind allgemeine Funktionen: Die Methoden für die internen Datums- / Zeitklassen werden hier dokumentiert.

% /% {base} gibt die Ganzzahldivision AKA (x% /% y) an (bis zum Rundungsfehler)


Dies funktionierte für mich, während einige der anderen dies nicht taten.
Lernstatistiken am Beispiel

41

Es kann einen einfacheren Weg geben. Es ist keine Funktion, sondern nur eine Zeile.

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

z.B

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

Produziert:

[1] 69

Dies berechnet die Anzahl ganzer Monate zwischen den beiden Daten. Entfernen Sie die -1, wenn Sie den aktuellen Monat / Rest einschließen möchten, der kein ganzer Monat ist.


4
Dies führt nicht immer zu erwarteten Ergebnissen. length(seq(from=as.Date("2015-01-31"), to=as.Date("2015-03-31"), by='month')) = 3Auch length(seq(from=as.Date("2015-01-31"), to=as.Date("2015-04-30"), by='month')) = 3
Oktave1

15

In der R-Help-Mailingliste befindet sich eine Nachricht wie Ihre (zuvor habe ich eine CRAN-Liste erwähnt).

Hier der Link . Es gibt zwei Lösungsvorschläge:

  • Es gibt durchschnittlich 365,25 / 12 Tage pro Monat, daher gibt der folgende Ausdruck die Anzahl der Monate zwischen d1 und d2 an:
#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))
  • Eine andere Möglichkeit besteht darin, die Länge seq.Dateswie folgt zu ermitteln :
as.Date.numeric <- function(x) structure(floor(x+.001), class = "Date")
sapply(d2, function(d2) length(seq(d1, as.Date(d2), by = "month")))-1

2
Angenommen, alle Daten haben eine ganze Anzahl von Monaten zwischen sich, sind aber nützlich.
Anotherfred

5
library(lubridate)

case1: naive Funktion

mos<-function (begin, end) {
      mos1<-as.period(interval(ymd(begin),ymd(end)))
      mos<-mos1@year*12+mos1@month
      mos
}

Fall 2: Wenn Sie unabhängig von "Tag" nur "Monat" berücksichtigen müssen

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
}

Beispiel:

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

Intervall (mdy (20150101), mdy (20150228))% /% Monate (1) Verwenden Sie einfach das native Funktionsintervall des Schmiermittels.
Mtelesha

danke mtelesha. In meinem Unternehmen muss ich jedoch häufig die Anzahl der Monate von 2 Tagen berechnen. Zum Beispiel müssen die Monate zwischen 20150131 und 20150201 1 sein. Also habe ich die benutzerdefinierte Funktion 'mob' verwendet. Wissen Sie, wie man das mit Lubridat macht?
Hyunwoo Jeong

Ich denke, Sie könnten entweder month (ymd) - month (ymd) verwenden. Oder Sie können drei Spalten für Jahr, Monat und Tag erstellen.
Mtelesha

Sicher, aber im Falle eines anderen Jahres wird es nicht funktionieren. Zum Beispiel Monat (ymd (20170101)) - Monat (ymd (20161231)) = -11 nicht 1
hyunwoo jeong

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

Unterschied in Monaten = 12 * Unterschied in Jahren + Unterschied in Monaten.

Das Folgende muss möglicherweise unter Verwendung der ifelseBedingung für die Monatsabzüge korrigiert werden


Vielleicht ist es erwähnenswert, dass dies zu negativen Zahlen führt - also entweder Datum1 / Datum2 ändern oder verwenden abs(etc) . Ich denke, dies ist eine sehr einfache und unkomplizierte Lösung, um ein guestimate
paar

3

Für mich hat das funktioniert:

library(lubridate)

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

Die Ausgabe ist die Anzahl der Monate zwischen zwei Daten, die in einer Spalte des Pagos-Datenrahmens gespeichert sind.


Vielen Dank für Ihren Beitrag, aber dies gibt keine Dezimalstellen. Irgendein Rat?
Mohamed Rahouma

Ich fürchte, das gibt Ihnen nur die Anzahl der Monate. aber nicht mit Komma. Meiner Meinung nach sollte stattdessen in Tagen gerechnet werden. Ich könnte genauer für Ihren Fall sein.
EDUARDO ROLDAN

2

Sie können die Funktion as.yearmon () aus dem Zoo-Paket verwenden. Diese Funktion konvertiert eine Variable vom Typ Datum in eine Variable vom Typ Jahr-Monat. Sie können zwei Variablen vom Typ Jahr-Monat subtrahieren und dann mit 12 multiplizieren, um die Differenz in Monaten wie folgt zu erhalten:

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

2
Nur-Code-Antworten werden normalerweise nicht empfohlen. Können Sie eine Erklärung hinzufügen, warum dies funktioniert oder warum es besser ist als die anderen Lösungen?
Jason

@ Jason Gerade getan!
Zheng Feng

Dies funktioniert, as.yearmon()ist jedoch Teil des zooPakets und nicht Teil der R-Basis. Wenn Sie einen Zoo installiert haben:12 * (zoo::as.yearmon(Date1) - zoo::as.yearmon(Date2))
Mark Egge

0

Datumsunterschied in Monaten

$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);

0

Ein weiterer kurzer und bequemer Weg ist folgender:

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

[1] 338

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.