web-dev-qa-db-ja.com

週、月、四半期、年の観点から日付の違いを取得します

14.01.201326.03.2014と言う2つの日付があります。

週(?)、月(例14)、四半期(4)、年(1)の観点から、これら2つの日付の差を取得したいと思います。

これを取得する最良の方法を知っていますか?

58
ddg

これはどうですか:

# 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()as.yearqtr()はパッケージZooにあります。 year()はパッケージlubridateにあります。どう思いますか?

66
ddg

既存の回答はすべて不完全(IMO​​)であり、目的の出力について推測するか、目的の出力に柔軟性を提供しません。

OPの例とOPの予想される回答に基づいて、これらがあなたが探している答えだと思います(さらに、簡単に推測できる追加の例もあります)。

(これにはベースRのみが必要で、Zooや潤滑油は必要ありません)

日時オブジェクトに変換

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

日数の違い

差分を数日で使用して、後の回答を得ることができます

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

週の違い

週の違いは、difftime()units = "weeks"の特殊なケースです

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

これは、diff_in_daysを7(週7日)で除算することと同じであることに注意してください。

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

年差

同様のロジックで、diff_in_daysから年を導出できます

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

あなたは年の差分が「1」であると期待しているようですので、あなたはfloor()

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

四半期の差異

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

月の違い

これを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

私はこの質問が古いことを知っていますが、この問題を今すぐ解決しなければならなかったので、答えを追加すると思いました。それが役に立てば幸い。

41
rysqui

数週間、関数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

ただし、difftimeは、数週間にわたる期間では機能しません。
以下は、これらの期間にcut.POSIXtを使用する非常に準最適なソリューションですが、回避することができます。

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

ただし、これは時間間隔がまたがる月、四半期、または年の数であり、月、四半期、年で表される時間間隔の期間ではありません(期間が一定でないため)。 @SvenHohensteinの回答に対して行ったコメントを考慮すると、達成しようとしていることにnlevels(cut(seq1,"months")) - 1を使用できると思います。

13
plannapus

私は別の質問のためにこれを書いただけで、つまずいた。

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

使用例:

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

解決策は次のとおりです。

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

より正確な計算。つまり、完全でない週/月/四半期/年の週/月/四半期/年の数は、その週/月/四半期/年の暦日の端数です。たとえば、2016-02-22と2016-03-31の間の月数は8/29 + 31/31 = 1.27586です

コードとインラインの説明

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

上記の解決策が機能しない境界ケースがさらに見つかった場合はお知らせください。

1
chinsoon12

これを1か月間試してみてください

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