web-dev-qa-db-fra.com

Obtenez la différence entre les dates en termes de semaines, mois, trimestres et années

J'ai deux dates disons 14.01.2013 et 26.03.2014.

J'aimerais connaître la différence entre ces deux dates en termes de semaines (?), De mois (dans l'exemple 14), de trimestres (4) et d'années (1).

Connaissez-vous le meilleur moyen de l'obtenir?

50
ddg

et ça:

# 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() et as.yearqtr() sont dans le package Zoo. year() est dans le package lubridate. Qu'en pensez-vous?

62
ddg

Toutes les réponses existantes sont imparfaites (IMO) et émettent soit des hypothèses sur le résultat souhaité, soit ne fournissent pas de flexibilité pour le résultat souhaité. 

Sur la base des exemples du PO et des réponses attendues énoncées du PO, je pense que ce sont les réponses que vous recherchez (plus quelques exemples supplémentaires qui facilitent l'extrapolation). 

(Ceci ne nécessite que la base R et ne nécessite ni Zoo ni lubrifiant)

Convertir en objets date/heure

date_strings = c("14.01.2013", "26.03.2014")
datetimes = strptime(date_strings, format = "%d.%m.%Y") # convert to datetime objects

Différence en jours

Vous pouvez utiliser le diff en jours pour obtenir certaines de nos dernières réponses

diff_in_days = difftime(datetimes[2], datetimes[1], units = "days") # days
diff_in_days
#Time difference of 435.9583 days

Différence en semaines

La différence en semaines est un cas particulier de units = "weeks" dans difftime()

diff_in_weeks = difftime(datetimes[2], datetimes[1], units = "weeks") # weeks
diff_in_weeks
#Time difference of 62.27976 weeks

Notez que cela revient à diviser notre diff_in_days par 7 (7 jours par semaine).

as.double(diff_in_days)/7
#[1] 62.27976

Différence en années

Avec une logique similaire, nous pouvons dériver des années de diff_in_days

diff_in_years = as.double(diff_in_days)/365 # absolute years
diff_in_years
#[1] 1.194406

Vous semblez vous attendre à ce que le diff des années soit égal à "1", alors je suppose que vous voulez simplement compter les années civiles absolues ou quelque chose que vous pouvez facilement faire en utilisant floor()

# get desired output, given your definition of 'years'
floor(diff_in_years)
#[1] 1

Différence en quart

# get desired output for quarters, given your definition of 'quarters'
floor(diff_in_years * 4)
#[1] 4

Différence en mois

Peut calculer cela comme une conversion de diff_years

# 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

Je sais que cette question est ancienne, mais comme il me restait à résoudre ce problème tout à l'heure, j'ai pensé ajouter mes réponses. J'espère que ça aide. 

36
rysqui

Pendant des semaines, vous pouvez utiliser la fonction 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

Mais difftime ne fonctionne pas avec une durée sur plusieurs semaines.
Ce qui suit est une solution très sous-optimale utilisant cut.POSIXt pour ces durées, mais vous pouvez la contourner:

seq1 <- seq(date1,date2, by="days")
nlevels(cut(seq1,"months"))
15
nlevels(cut(seq1,"quarters"))
5
nlevels(cut(seq1,"years"))
2

Il s’agit toutefois du nombre de mois, trimestres ou années couverts par votre intervalle de temps et non de la durée de votre intervalle de temps exprimée en mois, trimestres, années (car celles-ci n’ont pas une durée constante). Compte tenu de votre commentaire sur la réponse de @SvenHohenstein, je pense que vous pouvez utiliser nlevels(cut(seq1,"months")) - 1 pour ce que vous essayez d’atteindre.

13
plannapus

Je viens d'écrire ceci pour une autre question, puis suis tombé ici.

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

Exemples d'utilisation:

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
12
Gregor

Voici une solution: 

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
3
Sven Hohenstein

Un calcul plus "précis". En d’autres termes, le nombre de semaines/mois/trimestre/année d’une semaine/mois/trimestre/année non complète est la fraction de jours de calendrier de cette semaine/mois/trimestre/année. Par exemple, le nombre de mois entre le 22/02/2016 et le 31/03/2016 est 8/29 + 31/31 = 1.27586

explication en ligne avec le 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

Faites-moi savoir si vous trouvez plus de cas limites où la solution ci-dessus ne fonctionne pas.

1
chinsoon12

essayez ceci pour une solution de mois

StartDate <- strptime("14 January 2013", "%d %B %Y") 
EventDates <- strptime(c("26 March 2014"), "%d %B %Y") 
difftime(EventDates, StartDate) 
0
Rachel Gallen