I have a long list of start dates of a certain procedure. Rules require the procedure to be completed in, at most, 6 business days. I wish to compute the deadline.
Using lubridate in R, I can get a six-day deadline thus
> library(lubridate)
> date.in <- dmy(c("30-8-2001", "12-1-2003", "28-2-2003", "20-5-2004"))
> date.in
[1] "2001-08-30 UTC" "2003-01-12 UTC" "2003-02-28 UTC" "2004-05-20 UTC"
> deadline.using.days <- date.in + days(6)
> deadline.using.days
[1] "2001-09-05 UTC" "2003-01-18 UTC" "2003-03-06 UTC" "2004-05-26 UTC"
Is there an easy way to add six business days --- i.e., skipping Saturdays and Sundays? Thank you.
The package bizdays
has the function offset
which offsets the given dates by a number of business days.
It relies on the calendar you define and of course you can define a calendar where weekends are the only nonworking days.
Here is an example:
library(lubridate)
library(bizdays)
cal <- Calendar(weekdays=c('saturday', 'sunday'))
date.in <- dmy(c("30-8-2001", "12-1-2003", "28-2-2003", "20-5-2004"))
bizdays::offset(date.in, 6, cal)
# [1] "2001-09-07" "2003-01-21" "2003-03-10" "2004-05-28"
2018 Update
The function Calendar
in bizdays
has been renamed to create.calendar
,
but (in April 2018) a warning is no longer issued.
The code should now be slightly different:
library(lubridate)
library(bizdays)
create.calendar(name="mycal", weekdays=c('saturday', 'sunday'))
date.in <- dmy(c("30-8-2001", "12-1-2003", "28-2-2003", "20-5-2004"))
bizdays::offset(date.in, 6, "mycal")
# [1] "2001-09-07" "2003-01-21" "2003-03-10" "2004-05-28"
Here's a little infix function that adds offsets in terms of weekdays:
`%+wday%` <- function (x, i) {
if (!inherits(x, "Date"))
stop("x must be of class 'Date'")
if (!is.integer(i) && !is.numeric(i) && !all(i == as.integer(i)))
stop("i must be coercible to integer")
if ((length(x) != length(i)) && (length(x) != 1) && length(i) !=
1)
stop("'x' and 'i' must have equal length or lenght == 1")
if (!is.integer(i))
i = as.integer(i)
wd = lubridate::wday(x)
saturdays <- wd == 7
sundays <- wd == 1
if (any(saturdays) || any(sundays))
warning("weekend dates are coerced to the previous Friday before applying weekday shift")
x <- (x - saturdays * 1)
x <- (x - sundays * 2)
wd <- wd - saturdays * 1 + sundays * 5
x + 7 * (i%/%5) + i%%5 + 2 * (wd - 2 > 4 - i%%5)
}
Usage:
Sys.Date() %+wday% + 1:7
There's a nifty function isBizday
in the timeDate
package that made this more fun than it seemed on first glance.
date.in <- dmy(c("30-8-2001", "12-1-2003", "28-2-2003", "20-5-2004"))
Here's a function to do the work. It seemed reasonable to choose 1:10
for the days to look ahead, but that can be adjusted of course.
deadline <- function(x) {
days <- x + 1:10
Deadline <- days[isBizday(as.timeDate(days))][6]
data.frame(DateIn = x, Deadline, DayOfWeek = weekdays(Deadline),
TimeDiff = difftime(Deadline, x))
}
And here's the result:
library(timeDate)
Reduce(rbind, Map(deadline, as.Date(date.in)))
# DateIn Deadline DayOfWeek TimeDiff
# 1 2001-08-30 2001-09-07 Friday 8 days
# 2 2003-01-12 2003-01-20 Monday 8 days
# 3 2003-02-28 2003-03-10 Monday 10 days
# 4 2004-05-20 2004-05-28 Friday 8 days
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With