[更新]
在另一个thread中,来自@Frank的答案解决了这个问题。这个问题与另一个问题重复。
[问题]
我正在R
编写一个函数来测试工作日是否介于两个日期之间。这就是我所拥有的,但我认为解决方案并不优雅。有更多的数学方法吗?
library(data.table) ## wday is a function in this package
isDayIn <- function(weekday, date1, date2) {
if (weekday<1 | weekday>7) stop("weekday must be an integer from 1 to 7.")
date1 <- as.Date(date1)
date2 <- as.Date(date2)
output <- weekday %in% unique(wday(seq.Date(date1, date2, by=1)))
return(output)
}
## 2015-08-02 is a Sunday and 2015-08-03 is a Monday
isDayIn(1, "2015-08-02", "2015-08-03")
> TRUE
isDayIn(7, "2015-08-02", "2015-08-03")
> FALSE
注意:函数wday
在星期日开始,在星期六结束,因此星期日将映射到整数1,星期六将映射到整数7。
答案 0 :(得分:2)
使用var example = momentObject.format("YYYY-MM-DD[T]HH:mm:ss");
的另一个功能选项:
base R
答案 1 :(得分:1)
我认为您的解决方案很好。但这是一个快速修复:
isDayIn <- function(weekday, date1, date2) {
if (weekday<1 | weekday>7) stop("weekday must be an integer from 1 to 7.")
require(lubridate)
date1 <- as.Date(date1)
date2 <- as.Date(date2)
if (as.integer(date2 - date1) >= 7) {
return(TRUE) # by default
} else {
return(weekday %in% wday(seq.Date(date1, date2, by=1)))
}
}
答案 2 :(得分:0)
已经有很好的解决方案,但它们都没有避免产生一系列日子。我试图找到一个只比较工作日数字(和周数)的解决方案。
它在内部使用星期一作为一周的第一天,但参数startWithSunday
提供了将星期日设置为第1天的可能性。另一种方法是在%V
和%U
之间切换{ {1}},但这种方法对我来说似乎更直接。
strftime
这个小任务看起来像很多代码,但大部分只是准备;实际工作是在两个isDayIn1 <- function(weekday, date1, date2, startWithSunday = FALSE) {
if (weekday < 1 | weekday > 7) stop("weekday must be an integer from 1 to 7.")
if(startWithSunday) {
weekday <- max(weekday - 1, 1)
}
dates <- sort(as.Date(c(date1, date2)))
if (dates[2] - dates[1] >= 7) return(TRUE)
weeks <- strftime(dates, "%V")
days <- strftime(dates, "%u")
if (weeks[1] == weeks[2]) { # Dates are in the same week.
return(weekday >= days[1] & weekday <= days[2])
} else { # Different weeks.
return(weekday >= days[1] | weekday <= days[2])
}
}
语句中完成的。诀窍是区分日期在不同周内的情况,因为这会影响我们应该做的比较。
为了检查return
是否正常工作,我编写了这个小包装函数:
isDayIn1
这是第一批测试。请注意,niceTests <- function(weekday, date1, date2, startWithSunday = FALSE) {
date1 <- as.Date(date1)
date2 <- as.Date(date2)
fmt <- "%a, %y-%m-%d (week %V)"
if (startWithSunday) {
fmt <- "%a, %y-%m-%d (week %U)"
}
print(sprintf("Date1: %s, Date2: %s, Diff.: %d. Range contains day #%d: %s",
strftime(date1, fmt),
strftime(date2, fmt),
abs(date2 - date1),
weekday,
as.character(isDayIn1(weekday, date1, date2, startWithSunday))
))
}
默认为startWithSunday
,因此工作日FALSE
表示星期一。
1
输出:
niceTests(7, "2015-08-02", "2015-08-03") # from question (Sunday in Su-Mo)
niceTests(6, "2015-08-02", "2015-08-03") # from question (Saturday in Su-Mo)
niceTests(1, "2015-08-02", "2015-08-09") # Full week or more.
niceTests(1, "2015-08-02", "2015-08-10") # Full week or more.
niceTests(1, "2015-08-05", "2015-08-07") # Same week. (Wednesday - Friday)
niceTests(2, "2015-08-05", "2015-08-07") # Same week.
niceTests(3, "2015-08-05", "2015-08-07") # Same week.
niceTests(4, "2015-08-05", "2015-08-07") # Same week.
niceTests(5, "2015-08-05", "2015-08-07") # Same week.
niceTests(6, "2015-08-05", "2015-08-07") # Same week.
niceTests(7, "2015-08-05", "2015-08-07") # Same week.
niceTests(1, "2015-08-08", "2015-08-11") # Across weeks. (Saturday - Tuesday)
niceTests(2, "2015-08-08", "2015-08-11") # Across weeks.
niceTests(3, "2015-08-08", "2015-08-11") # Across weeks.
niceTests(4, "2015-08-08", "2015-08-11") # Across weeks.
niceTests(5, "2015-08-08", "2015-08-11") # Across weeks.
niceTests(6, "2015-08-08", "2015-08-11") # Across weeks.
niceTests(7, "2015-08-08", "2015-08-11") # Across weeks.
最后,[1] "Date1: Sun, 15-08-02 (week 31), Date2: Mon, 15-08-03 (week 32), Diff.: 1. Range contains day #7: TRUE"
[1] "Date1: Sun, 15-08-02 (week 31), Date2: Mon, 15-08-03 (week 32), Diff.: 1. Range contains day #6: FALSE"
[1] "Date1: Sun, 15-08-02 (week 31), Date2: Sun, 15-08-09 (week 32), Diff.: 7. Range contains day #1: TRUE"
[1] "Date1: Sun, 15-08-02 (week 31), Date2: Mon, 15-08-10 (week 33), Diff.: 8. Range contains day #1: TRUE"
[1] "Date1: Wed, 15-08-05 (week 32), Date2: Fri, 15-08-07 (week 32), Diff.: 2. Range contains day #1: FALSE"
[1] "Date1: Wed, 15-08-05 (week 32), Date2: Fri, 15-08-07 (week 32), Diff.: 2. Range contains day #2: FALSE"
[1] "Date1: Wed, 15-08-05 (week 32), Date2: Fri, 15-08-07 (week 32), Diff.: 2. Range contains day #3: TRUE"
[1] "Date1: Wed, 15-08-05 (week 32), Date2: Fri, 15-08-07 (week 32), Diff.: 2. Range contains day #4: TRUE"
[1] "Date1: Wed, 15-08-05 (week 32), Date2: Fri, 15-08-07 (week 32), Diff.: 2. Range contains day #5: TRUE"
[1] "Date1: Wed, 15-08-05 (week 32), Date2: Fri, 15-08-07 (week 32), Diff.: 2. Range contains day #6: FALSE"
[1] "Date1: Wed, 15-08-05 (week 32), Date2: Fri, 15-08-07 (week 32), Diff.: 2. Range contains day #7: FALSE"
[1] "Date1: Sat, 15-08-08 (week 32), Date2: Tue, 15-08-11 (week 33), Diff.: 3. Range contains day #1: TRUE"
[1] "Date1: Sat, 15-08-08 (week 32), Date2: Tue, 15-08-11 (week 33), Diff.: 3. Range contains day #2: TRUE"
[1] "Date1: Sat, 15-08-08 (week 32), Date2: Tue, 15-08-11 (week 33), Diff.: 3. Range contains day #3: FALSE"
[1] "Date1: Sat, 15-08-08 (week 32), Date2: Tue, 15-08-11 (week 33), Diff.: 3. Range contains day #4: FALSE"
[1] "Date1: Sat, 15-08-08 (week 32), Date2: Tue, 15-08-11 (week 33), Diff.: 3. Range contains day #5: FALSE"
[1] "Date1: Sat, 15-08-08 (week 32), Date2: Tue, 15-08-11 (week 33), Diff.: 3. Range contains day #6: TRUE"
[1] "Date1: Sat, 15-08-08 (week 32), Date2: Tue, 15-08-11 (week 33), Diff.: 3. Range contains day #7: TRUE"
的测试,其中第1天是星期日:
startWidthSunday = TRUE
输出:
print("Now: Start with Sunday!")
niceTests(1, "2015-08-02", "2015-08-03", startWithSunday = TRUE) # from question (Sunday in Su-Mo)
niceTests(7, "2015-08-02", "2015-08-03", startWithSunday = TRUE) # from question (Saturday in Su-Mo)
niceTests(1, "2015-08-02", "2015-08-09", startWithSunday = TRUE) # Full week or more.
niceTests(1, "2015-08-02", "2015-08-10", startWithSunday = TRUE) # Full week or more.
niceTests(1, "2015-08-05", "2015-08-07", startWithSunday = TRUE) # Same week. (Wednesday - Friday)
niceTests(2, "2015-08-05", "2015-08-07", startWithSunday = TRUE) # Same week.
niceTests(3, "2015-08-05", "2015-08-07", startWithSunday = TRUE) # Same week.
niceTests(4, "2015-08-05", "2015-08-07", startWithSunday = TRUE) # Same week.
niceTests(5, "2015-08-05", "2015-08-07", startWithSunday = TRUE) # Same week.
niceTests(6, "2015-08-05", "2015-08-07", startWithSunday = TRUE) # Same week.
niceTests(7, "2015-08-05", "2015-08-07", startWithSunday = TRUE) # Same week.
niceTests(1, "2015-08-08", "2015-08-11", startWithSunday = TRUE) # Across weeks. (Saturday - Tuesday)
niceTests(2, "2015-08-08", "2015-08-11", startWithSunday = TRUE) # Across weeks.
niceTests(3, "2015-08-08", "2015-08-11", startWithSunday = TRUE) # Across weeks.
niceTests(4, "2015-08-08", "2015-08-11", startWithSunday = TRUE) # Across weeks.
niceTests(5, "2015-08-08", "2015-08-11", startWithSunday = TRUE) # Across weeks.
niceTests(6, "2015-08-08", "2015-08-11", startWithSunday = TRUE) # Across weeks.
niceTests(7, "2015-08-08", "2015-08-11", startWithSunday = TRUE) # Across weeks.
答案 3 :(得分:0)
我通过@CL编写了答案的矢量化版本,该版本也更为通用:
#' 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)
}
例如,假设我们要检测一个与周末重叠的时间序列中的间隔。我们在周六和周日运行wday_in_interval
:
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
)
结果:
# 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
在我的中型笔记本电脑上,它在约3秒内处理了250.000行。