2015-08-05 3 views
2

[Обновление]Определить, если будний день между двумя датами в R

В другом 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

ли вы объяснить, почему второй вызов должен быть ложным? День 7 (воскресенье, я полагаю) * * в указанном диапазоне. –

+0

Необходимо отметить пакет (ы), который вы используете. 'wday' определяется в' lubridate' и 'data.table', но не в базе ** R **. –

+0

@ user2706569 'wday' начинается с воскресенья и заканчивается субботой. Вы можете найти дополнительную информацию из '? Data.table :: wday'. – Boxuan

ответ

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

Это выглядит как хорошее улучшение, потому что оно не будет извлекать весь диапазон и сканировать для uniques, когда диапазон дат станет большим. Тем не менее, мне все же хотелось бы знать, есть ли математический способ обработки 'weekday% in% unique (wday (seq.Date (date1, date2, by = 1))), например, модуля. В противном случае это отличное решение. – Boxuan

2

Другой вариант функции с помощью base R:

isDayIn <- function(weekday, date1, date2) { 
    if (weekday<1 | weekday>7) stop("weekday must be an integer from 1 to 7.") 
    weekday %in% strftime(seq(as.Date(date1), as.Date(date2), by="day"), format="%w") 
} 

isDayIn(1, "2015-08-02", "2015-08-03") 
[1] TRUE 
isDayIn(7, "2015-08-02", "2015-08-03") 
[1] FALSE 
0

Там уже есть хорошие решения, но ни один из них не позволяет избежать формирования последовательности дней. Я попытался найти решение, которое просто сравнивает число дней недели (и недели). Он использует свой понедельник как первый день недели, но аргумент startWithSunday дает возможность установить воскресенье как день 1. Альтернативой было бы переключение между %V и %U в 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" 

Наконец, тесты на startWidthSunday = TRUE где день 1 является воскресенье:

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. 

Выход:

[1] "Now: Start with Sunday!" 
[1] "Date1: Sun, 15-08-02 (week 31), Date2: Mon, 15-08-03 (week 31), Diff.: 1. Range contains day #1: TRUE" 
[1] "Date1: Sun, 15-08-02 (week 31), Date2: Mon, 15-08-03 (week 31), Diff.: 1. Range contains day #7: 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 32), Diff.: 8. Range contains day #1: TRUE" 
[1] "Date1: Wed, 15-08-05 (week 31), Date2: Fri, 15-08-07 (week 31), Diff.: 2. Range contains day #1: FALSE" 
[1] "Date1: Wed, 15-08-05 (week 31), Date2: Fri, 15-08-07 (week 31), Diff.: 2. Range contains day #2: FALSE" 
[1] "Date1: Wed, 15-08-05 (week 31), Date2: Fri, 15-08-07 (week 31), Diff.: 2. Range contains day #3: FALSE" 
[1] "Date1: Wed, 15-08-05 (week 31), Date2: Fri, 15-08-07 (week 31), Diff.: 2. Range contains day #4: TRUE" 
[1] "Date1: Wed, 15-08-05 (week 31), Date2: Fri, 15-08-07 (week 31), Diff.: 2. Range contains day #5: TRUE" 
[1] "Date1: Wed, 15-08-05 (week 31), Date2: Fri, 15-08-07 (week 31), Diff.: 2. Range contains day #6: TRUE" 
[1] "Date1: Wed, 15-08-05 (week 31), Date2: Fri, 15-08-07 (week 31), Diff.: 2. Range contains day #7: FALSE" 
[1] "Date1: Sat, 15-08-08 (week 31), Date2: Tue, 15-08-11 (week 32), Diff.: 3. Range contains day #1: TRUE" 
[1] "Date1: Sat, 15-08-08 (week 31), Date2: Tue, 15-08-11 (week 32), Diff.: 3. Range contains day #2: TRUE" 
[1] "Date1: Sat, 15-08-08 (week 31), Date2: Tue, 15-08-11 (week 32), Diff.: 3. Range contains day #3: TRUE" 
[1] "Date1: Sat, 15-08-08 (week 31), Date2: Tue, 15-08-11 (week 32), Diff.: 3. Range contains day #4: FALSE" 
[1] "Date1: Sat, 15-08-08 (week 31), Date2: Tue, 15-08-11 (week 32), Diff.: 3. Range contains day #5: FALSE" 
[1] "Date1: Sat, 15-08-08 (week 31), Date2: Tue, 15-08-11 (week 32), Diff.: 3. Range contains day #6: FALSE" 
[1] "Date1: Sat, 15-08-08 (week 31), Date2: Tue, 15-08-11 (week 32), Diff.: 3. Range contains day #7: TRUE" 
Смежные вопросы