Ich habe zwei Termine, sagen wir mal 14.01.2013
und 26.03.2014
.
Ich möchte die Differenz zwischen diesen beiden Daten in Wochen (?), Monaten (im Beispiel 14), Quartalen (4) und Jahren (1) ermitteln.
Kennen Sie den besten Weg, um dies zu bekommen?
Antworten:
was ist damit:
# get difference between dates `"01.12.2013"` and `"31.12.2013"` # weeks difftime(strptime("26.03.2014", format = "%d.%m.%Y"), strptime("14.01.2013", format = "%d.%m.%Y"),units="weeks") Time difference of 62.28571 weeks # months (as.yearmon(strptime("26.03.2014", format = "%d.%m.%Y"))- as.yearmon(strptime("14.01.2013", format = "%d.%m.%Y")))*12 [1] 14 # quarters (as.yearqtr(strptime("26.03.2014", format = "%d.%m.%Y"))- as.yearqtr(strptime("14.01.2013", format = "%d.%m.%Y")))*4 [1] 4 # years year(strptime("26.03.2014", format = "%d.%m.%Y"))- year(strptime("14.01.2013", format = "%d.%m.%Y")) [1] 1
as.yearmon()
undas.yearqtr()
sind im Paketzoo
.year()
ist im Paketlubridate
. Was denken Sie?quelle
year
in Kalenderjahren einen Unterschied. Wenn Sie also den Unterschied in einem Bruchteil eines Jahres kennen müssen, ist er nicht geeignet.Alle vorhandenen Antworten sind unvollständig (IMO) und treffen entweder Annahmen über die gewünschte Ausgabe oder bieten keine Flexibilität für die gewünschte Ausgabe.
Basierend auf den Beispielen aus dem OP und den angegebenen erwarteten Antworten des OP denke ich, dass dies die Antworten sind, nach denen Sie suchen (plus einige zusätzliche Beispiele, die die Extrapolation erleichtern).
(Dies erfordert nur Basis R und erfordert keinen Zoo oder Schmiermittel)
In Datetime-Objekte konvertieren
date_strings = c("14.01.2013", "26.03.2014") datetimes = strptime(date_strings, format = "%d.%m.%Y") # convert to datetime objects
Unterschied in Tagen
Sie können den Diff in Tagen verwenden, um einige unserer späteren Antworten zu erhalten
diff_in_days = difftime(datetimes[2], datetimes[1], units = "days") # days diff_in_days #Time difference of 435.9583 days
Unterschied in Wochen
Der Unterschied in Wochen ist ein Sonderfall von
units = "weeks"
indifftime()
diff_in_weeks = difftime(datetimes[2], datetimes[1], units = "weeks") # weeks diff_in_weeks #Time difference of 62.27976 weeks
Beachten Sie, dass dies dem Teilen unserer diff_in_days durch 7 (7 Tage in einer Woche) entspricht.
as.double(diff_in_days)/7 #[1] 62.27976
Unterschied in Jahren
Mit ähnlicher Logik können wir Jahre aus diff_in_days ableiten
diff_in_years = as.double(diff_in_days)/365 # absolute years diff_in_years #[1] 1.194406
Sie scheinen zu erwarten, dass der Unterschied in Jahren "1" ist, also gehe ich davon aus, dass Sie nur absolute Kalenderjahre oder etwas anderes zählen möchten, was Sie einfach mit verwenden können
floor()
# get desired output, given your definition of 'years' floor(diff_in_years) #[1] 1
Unterschied in Quartalen
# get desired output for quarters, given your definition of 'quarters' floor(diff_in_years * 4) #[1] 4
Unterschied in Monaten
Kann dies als Umrechnung von diff_years berechnen
# months, defined as absolute calendar months (this might be what you want, given your question details) months_diff = diff_in_years*12 floor(month_diff) #[1] 14
Ich weiß, dass diese Frage alt ist, aber da ich dieses Problem gerade noch lösen musste, dachte ich, ich würde meine Antworten hinzufügen. Ich hoffe es hilft.
quelle
months_diff
<0 ist.date_strings = c("14.07.2014", "10.03.2015")
Geben Sie-4
stattdessen 7 Monate gemäß der ersten Definition.diff_in_years
, z. B. in Ihrem Beispiel ist die wahre Antwort, dass fast 8 volle Monate vergangen sind. Sie erhalten die richtige Antwort, indemdiff_in_years*12 = 7.857534
ich meine Antwort korrigiere - danke.365
Jahre teilen , um Jahre zu erhalten, gilt dies aufgrund von Schaltjahren nur für 3 von 4 Jahren. Die Division durch365.25
wäre genauer, insbesondere für die Berechnung eines Alters.Wochenlang können Sie folgende Funktionen verwenden
difftime
:date1 <- strptime("14.01.2013", format="%d.%m.%Y") date2 <- strptime("26.03.2014", format="%d.%m.%Y") difftime(date2,date1,units="weeks") Time difference of 62.28571 weeks
Funktioniert aber
difftime
nicht mit Dauer über Wochen.Das Folgende ist eine sehr suboptimale Lösung
cut.POSIXt
für diese Zeiträume, aber Sie können sie umgehen:seq1 <- seq(date1,date2, by="days") nlevels(cut(seq1,"months")) 15 nlevels(cut(seq1,"quarters")) 5 nlevels(cut(seq1,"years")) 2
Dies ist jedoch die Anzahl der Monate, Quartale oder Jahre, die sich über Ihr Zeitintervall erstrecken, und nicht die Dauer Ihres Zeitintervalls, ausgedrückt in Monaten, Quartalen, Jahren (da diese keine konstante Dauer haben). In Anbetracht des Kommentars, den Sie zu @SvenHohenstein abgegeben haben, würde ich denken, dass Sie ihn
nlevels(cut(seq1,"months")) - 1
für das verwenden können, was Sie erreichen möchten .quelle
Ich habe das gerade für eine andere Frage geschrieben und bin dann hierher gestolpert.
library(lubridate) #' Calculate age #' #' By default, calculates the typical "age in years", with a #' \code{floor} applied so that you are, e.g., 5 years old from #' 5th birthday through the day before your 6th birthday. Set #' \code{floor = FALSE} to return decimal ages, and change \code{units} #' for units other than years. #' @param dob date-of-birth, the day to start calculating age. #' @param age.day the date on which age is to be calculated. #' @param units unit to measure age in. Defaults to \code{"years"}. Passed to \link{\code{duration}}. #' @param floor boolean for whether or not to floor the result. Defaults to \code{TRUE}. #' @return Age in \code{units}. Will be an integer if \code{floor = TRUE}. #' @examples #' my.dob <- as.Date('1983-10-20') #' age(my.dob) #' age(my.dob, units = "minutes") #' age(my.dob, floor = FALSE) age <- function(dob, age.day = today(), units = "years", floor = TRUE) { calc.age = interval(dob, age.day) / duration(num = 1, units = units) if (floor) return(as.integer(floor(calc.age))) return(calc.age) }
Anwendungsbeispiele:
my.dob <- as.Date('1983-10-20') age(my.dob) # [1] 31 age(my.dob, floor = FALSE) # [1] 31.15616 age(my.dob, units = "minutes") # [1] 16375680 age(seq(my.dob, length.out = 6, by = "years")) # [1] 31 30 29 28 27 26
quelle
if (floor) { ... }
und nur,return
wenn Sie etwas zur Hälfte Ihrer Funktion zurückgeben. Die letzte Zeile sollte einfach seincalc.age
.return
mit meinen Funktionen - ich finde es klarer. Verwenden Sie in Ihrem eigenen Code natürlich den Stil, der zu Ihnen passt.1950-01-17
und2015-01-01
. Es kehrt zurück65
, aber diese Person würde nicht vor dem 17.01.2015 65 Jahre alt werden ... Irgendeine Idee warum?yy = seq.Date(from = as.Date("2010-01-01"), to = as.Date("2015-01-01"), by = "year")
und dann versuchenage(dob = as.Date("1950-01-17"), age.day = yy)
, springt das Ergebnis über 62. Und nur wenn das Geburtsdatum zwischen 1949 und 1952 liegt. Sehr seltsam ...Hier ist eine Lösung:
dates <- c("14.01.2013", "26.03.2014") # Date format: dates2 <- strptime(dates, format = "%d.%m.%Y") dif <- diff(as.numeric(dates2)) # difference in seconds dif/(60 * 60 * 24 * 7) # weeks [1] 62.28571 dif/(60 * 60 * 24 * 30) # months [1] 14.53333 dif/(60 * 60 * 24 * 30 * 3) # quartes [1] 4.844444 dif/(60 * 60 * 24 * 365) # years [1] 1.194521
quelle
Termine sind hier ein großes Thema und die gegebenen Antworten sind großartig. Hier die noch ausstehende
lubridate
Antwort (obwohl die Funktion von @Gregor dieses Paket verwendet)Die Dokumentation zur Schmierzeitspanne ist sehr hilfreich, um den Unterschied zwischen Zeiträumen und Dauer zu verstehen. Ich mag auch das Lubridate Cheatsheet und diesen sehr nützlichen Thread
library(lubridate) dates <- c(dmy('14.01.2013'),dmy('26.03.2014')) span <- dates[1] %--% dates[2] #creating an interval object #creating period objects as.period(span, unit = 'year') #> [1] "1y 2m 12d 0H 0M 0S" as.period(span, unit = 'month') #> [1] "14m 12d 0H 0M 0S" as.period(span, unit = 'day') #> [1] "436d 0H 0M 0S"
Perioden akzeptieren keine Wochen als Einheiten. Sie können die Dauer jedoch in Wochen umrechnen :
as.duration(span)/ dweeks(1) #makes duration object (in seconds) and divides by duration of a week (in seconds) #> [1] 62.28571
Erstellt am 04.11.2019 durch das reprex-Paket (v0.3.0)
quelle
Versuchen Sie dies für eine monatelange Lösung
StartDate <- strptime("14 January 2013", "%d %B %Y") EventDates <- strptime(c("26 March 2014"), "%d %B %Y") difftime(EventDates, StartDate)
quelle
%m
numerische Monate (z. B. 1 für Januar) anstelle von zu verwenden%B
.Eine "genauere" Berechnung. Das heißt, die Anzahl der Woche / Monat / Quartal / Jahr für eine nicht vollständige Woche / Monat / Quartal / Jahr ist der Bruchteil der Kalendertage in dieser Woche / Monat / Quartal / Jahr. Beispielsweise beträgt die Anzahl der Monate zwischen dem 22.02.2016 und dem 31.03.2016 8/29 + 31/31 = 1,27586
Erklärung inline mit Code
#' Calculate precise number of periods between 2 dates #' #' @details The number of week/month/quarter/year for a non-complete week/month/quarter/year #' is the fraction of calendar days in that week/month/quarter/year. #' For example, the number of months between 2016-02-22 and 2016-03-31 #' is 8/29 + 31/31 = 1.27586 #' #' @param startdate start Date of the interval #' @param enddate end Date of the interval #' @param period character. It must be one of 'day', 'week', 'month', 'quarter' and 'year' #' #' @examples #' identical(numPeriods(as.Date("2016-02-15"), as.Date("2016-03-31"), "month"), 15/29 + 1) #' identical(numPeriods(as.Date("2016-02-15"), as.Date("2016-03-31"), "quarter"), (15 + 31)/(31 + 29 + 31)) #' identical(numPeriods(as.Date("2016-02-15"), as.Date("2016-03-31"), "year"), (15 + 31)/366) #' #' @return exact number of periods between #' numPeriods <- function(startdate, enddate, period) { numdays <- as.numeric(enddate - startdate) + 1 if (grepl("day", period, ignore.case=TRUE)) { return(numdays) } else if (grepl("week", period, ignore.case=TRUE)) { return(numdays / 7) } #create a sequence of dates between start and end dates effDaysinBins <- cut(seq(startdate, enddate, by="1 day"), period) #use the earliest start date of the previous bins and create a breaks of periodic dates with #user's period interval intervals <- seq(from=as.Date(min(levels(effDaysinBins)), "%Y-%m-%d"), by=paste("1",period), length.out=length(levels(effDaysinBins))+1) #create a sequence of dates between the earliest interval date and last date of the interval #that contains the enddate allDays <- seq(from=intervals[1], to=intervals[intervals > enddate][1] - 1, by="1 day") #bin all days in the whole period using previous breaks allDaysInBins <- cut(allDays, intervals) #calculate ratio of effective days to all days in whole period sum( tabulate(effDaysinBins) / tabulate(allDaysInBins) ) } #numPeriods
Bitte lassen Sie mich wissen, wenn Sie weitere Grenzfälle finden, in denen die oben genannte Lösung nicht funktioniert.
quelle