Tôi có hai ngày để nói 14.01.2013
và 26.03.2014
.
Tôi muốn nhận được sự khác biệt giữa hai ngày đó theo tuần (?), Tháng (trong ví dụ 14), quý (4) và năm (1).
Bạn có biết cách tốt nhất để có được điều này?
Tôi có hai ngày để nói 14.01.2013
và 26.03.2014
.
Tôi muốn nhận được sự khác biệt giữa hai ngày đó theo tuần (?), Tháng (trong ví dụ 14), quý (4) và năm (1).
Bạn có biết cách tốt nhất để có được điều này?
Câu trả lời:
cái này thì sao:
# 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()
và as.yearqtr()
đang trong gói zoo
. year()
là trong gói lubridate
. Bạn nghĩ sao?
year
sẽ chỉ cung cấp sự khác biệt trong các năm dương lịch , vì vậy nếu bạn cần biết sự khác biệt trong một số phần của năm, nó sẽ không phù hợp.
Tất cả các câu trả lời hiện có là không hoàn hảo (IMO) và đưa ra giả định về đầu ra mong muốn hoặc không cung cấp tính linh hoạt cho đầu ra mong muốn.
Dựa trên các ví dụ từ OP và các câu trả lời mong đợi đã nêu của OP, tôi nghĩ rằng đây là những câu trả lời bạn đang tìm kiếm (cộng với một số ví dụ bổ sung giúp dễ dàng ngoại suy).
(Điều này chỉ yêu cầu cơ sở R và không yêu cầu sở thú hoặc lubridate)
Chuyển đổi thành đối tượng ngày giờ
date_strings = c("14.01.2013", "26.03.2014")
datetimes = strptime(date_strings, format = "%d.%m.%Y") # convert to datetime objects
Sự khác biệt về ngày
Bạn có thể sử dụng sự khác biệt trong ngày để nhận được một số câu trả lời sau của chúng tôi
diff_in_days = difftime(datetimes[2], datetimes[1], units = "days") # days
diff_in_days
#Time difference of 435.9583 days
Sự khác biệt trong các tuần
Sự khác biệt trong những tuần là một trường hợp đặc biệt của units = "weeks"
trongdifftime()
diff_in_weeks = difftime(datetimes[2], datetimes[1], units = "weeks") # weeks
diff_in_weeks
#Time difference of 62.27976 weeks
Lưu ý rằng điều này giống như chia diff_in_days của chúng tôi cho 7 (7 ngày trong một tuần)
as.double(diff_in_days)/7
#[1] 62.27976
Sự khác biệt theo năm
Với logic tương tự, chúng ta có thể tính được năm từ diff_in_days
diff_in_years = as.double(diff_in_days)/365 # absolute years
diff_in_years
#[1] 1.194406
Có vẻ như bạn đang mong đợi chênh lệch theo năm là "1", vì vậy, tôi giả sử bạn chỉ muốn đếm số năm theo lịch tuyệt đối hoặc điều gì đó, bạn có thể dễ dàng thực hiện bằng cách sử dụng floor()
# get desired output, given your definition of 'years'
floor(diff_in_years)
#[1] 1
Sự khác biệt trong các khu
# get desired output for quarters, given your definition of 'quarters'
floor(diff_in_years * 4)
#[1] 4
Sự khác biệt trong các tháng
Có thể tính toán điều này như một chuyển đổi từ 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
Tôi biết câu hỏi này đã cũ, nhưng vì tôi vẫn phải giải quyết vấn đề này vừa rồi, tôi nghĩ tôi sẽ thêm câu trả lời của mình. Hy vọng nó giúp.
months_diff
là <0.
date_strings = c("14.07.2014", "10.03.2015")
cho -4
thay vì 7 tháng theo định nghĩa đầu tiên ..
diff_in_years
ví dụ, trong ví dụ của bạn, câu trả lời đúng là gần 8 tháng đã qua. Bạn nhận được câu trả lời chính xác chỉ bằng cách diff_in_years*12 = 7.857534
tôi sửa câu trả lời của mình - cảm ơn.
365
cho các năm, nó chỉ áp dụng cho 3 trong số 4 năm, do năm nhuận. Chia cho 365.25
sẽ chính xác hơn, đặc biệt là để tính tuổi.
Trong nhiều tuần, bạn có thể sử dụng chức năng 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
Nhưng difftime
không hoạt động với thời gian kéo dài hàng tuần.
Sau đây là một giải pháp rất tối ưu sử dụng cut.POSIXt
cho những khoảng thời gian đó nhưng bạn có thể khắc phục nó:
seq1 <- seq(date1,date2, by="days")
nlevels(cut(seq1,"months"))
15
nlevels(cut(seq1,"quarters"))
5
nlevels(cut(seq1,"years"))
2
Tuy nhiên, đây là số tháng, quý hoặc năm trải dài bởi khoảng thời gian của bạn chứ không phải khoảng thời gian của khoảng thời gian được biểu thị bằng tháng, quý, năm (vì những khoảng thời gian đó không có thời hạn cố định). Xem xét nhận xét bạn đưa ra về câu trả lời @SvenHohenstein, tôi nghĩ bạn có thể sử dụng nlevels(cut(seq1,"months")) - 1
cho những gì bạn đang cố gắng đạt được.
Tôi chỉ viết cái này cho một câu hỏi khác, sau đó vấp phải ở đây.
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)
}
Các ví dụ sử dụng:
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
if (floor) { ... }
và chỉ sử dụng return
khi bạn đang trả về một thứ gì đó ở nửa hàm của mình. Dòng cuối cùng nên được calc.age
.
return
với các chức năng của mình - tôi thấy nó rõ ràng hơn. Tất nhiên, trong mã của riêng bạn, hãy sử dụng bất kỳ phong cách nào phù hợp với bạn.
1950-01-17
và 2015-01-01
. Nó quay trở lại 65
, nhưng người này sẽ không bước sang tuổi 65 trước 2015-01-17 ... Bạn có biết tại sao không?
yy = seq.Date(from = as.Date("2010-01-01"), to = as.Date("2015-01-01"), by = "year")
và sau đó cố gắng age(dob = as.Date("1950-01-17"), age.day = yy)
, kết quả nhảy qua 62. Và chỉ khi DOB là giữa năm 1949 và 1952. Rất lạ ...
Đây là một giải pháp:
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
Đây là lubridate
câu trả lời vẫn còn thiếu (mặc dù chức năng của Gregor được xây dựng trên gói này)
Các tài liệu lubridate khoảng thời gian là rất hữu ích trong việc tìm hiểu sự khác biệt giữa thời gian và thời gian. Tôi cũng thích bảng lừa đảo lubridate và chủ đề rất hữu ích này
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"
Khoảng thời gian không chấp nhận tuần làm đơn vị. Nhưng bạn có thể chuyển đổi thời lượng thành tuần:
as.duration(span)/ dweeks(1)
#makes duration object (in seconds) and divides by duration of a week (in seconds)
#> [1] 62.28571
Được tạo vào ngày 11 tháng 11 năm 2019 bởi gói reprex (v0.3.0)
thử giải pháp này cho một tháng
StartDate <- strptime("14 January 2013", "%d %B %Y")
EventDates <- strptime(c("26 March 2014"), "%d %B %Y")
difftime(EventDates, StartDate)
%m
và các tháng bằng số (ví dụ: 1 cho tháng 1) thay vì %B
.
Một phép tính "chính xác" hơn. Tức là, số tuần / tháng / quý / năm của một tuần / tháng / quý / năm không hoàn thành là phần nhỏ của số ngày dương lịch trong tuần / tháng / quý / năm đó. Ví dụ: số tháng giữa 2016-02-22 và 2016-03-31 là 8/29 + 31/31 = 1.27586
giải thích nội dòng với mã
#' 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
Vui lòng cho tôi biết nếu bạn tìm thấy thêm các trường hợp ranh giới mà giải pháp trên không hoạt động.