I have a series of arrival and leaving dates. I want to know if those dates overlap a weekend. I could write a custom function to walk each of the days in the interval and see if they are a weekend. Is there a simpler way to do this that will scale better?
I am using lubridate, but I'm happy to use a different date package if that would make my job easier.
How about this base-R solution:
# make a set of sequences from beginning and ending dates and test with:
as.POSIXlt(x)$wday %in% c(0,6)
That would deliver a vector of TRUE/FALSE and you could determine whether any of the items in the sequence were TRUE with:
max( as.POSIXlt(x)$wday %in% c(0,6) )
With a_date as arrival date and d_date ansd departure date, something like this could work:
require(lubridate)
weekend_overlap <- ifelse(wday(a_date) %in% c(1, 7) ||
wday(d_date) %in% c(1, 7) ||
interval(a_date,d_date)/ddays(1) > 4,TRUE,FALSE)
Here is a more general (vectorized) function that checks whether the interval from
- to
contains a certain weekday (1-7):
#' Check if a weekday is within an interval
#'
#' @param wday Day of week (integer 1-7)
#' @param from Date. Can be a vector.
#' @param to Date. Same length as `from` and must be greater than `from`.
#' @param week_start 1 = Monday. 7 = Sunday
#'
wday_in_interval = function(wday, from, to, week_start = 1) {
if (wday < 1 | weekday > 7)
stop("wday must be an integer from 1 to 7.")
if (week_start)
wday = 1 + (((wday - 2) + week_start ) %% 7) # Translate wday to week_start = 1 (ISO standard)
if (any(from > to, na.rm = TRUE))
stop("`from` must come before `to`")
# If the interval is greater than a week, it trivially contains any weekday
over_a_week = difftime(from, to, units = "days") >= 7
# Check if weekday is both smaller/greater than "from" and "to"
days_from = as.numeric(strftime(from, "%u"))
days_to = as.numeric(strftime(to, "%u"))
contains_weekday = ifelse(
strftime(from, "%V") == strftime(to, "%V"), # Dates are in the same week?
yes = wday >= days_from & wday <= days_to,
no = wday >= days_from | wday <= days_to #
)
return(over_a_week | contains_weekday)
}
Finding out whether an interval includes a weekend is then just a matter of checking that the interval does not include Saturdays OR Sundays:
library(dplyr)
tibble::tibble(
timestamp = seq(as.POSIXct("2020-09-03 0:00"), as.POSIXct("2020-09-8 12: 00"), length.out = 10),
overlaps_saturday = wday_in_interval(6, from = lag(timestamp), to = timestamp),
overlaps_sunday = wday_in_interval(7, from = lag(timestamp), to = timestamp),
overlaps_weekend = overlaps_saturday | overlaps_sunday
)
Result:
# A tibble: 10 x 4
timestamp overlaps_saturday overlaps_sunday overlaps_weekend
<dttm> <lgl> <lgl> <lgl>
1 2020-09-03 00:00:00 NA NA NA
2 2020-09-03 14:40:00 FALSE FALSE FALSE
3 2020-09-04 05:20:00 FALSE FALSE FALSE
4 2020-09-04 20:00:00 FALSE FALSE FALSE
5 2020-09-05 10:40:00 TRUE FALSE TRUE
6 2020-09-06 01:20:00 TRUE TRUE TRUE
7 2020-09-06 16:00:00 FALSE TRUE TRUE
8 2020-09-07 06:40:00 FALSE TRUE TRUE
9 2020-09-07 21:20:00 FALSE FALSE FALSE
10 2020-09-08 12:00:00 FALSE FALSE FALSE
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.