簡體   English   中英

計算R中2個日期之間的工作日數

[英]Calculate the number of weekdays between 2 dates in R

我正在嘗試編寫一個R函數來計算兩個日期之間的工作日數。 例如,Nweekdays('01 / 30/2011','02/04/2011')等於5。

此問題類似。 謝謝!

/編輯:@J。 溫徹斯特的答案很棒,但我想知道是否有人能想出一種方法來對此進行矢量化,以便它可以在兩列日期上工作。 謝謝! /編輯2:再次感謝!

Date1 <- as.Date("2011-01-30")
Date2 <- as.Date("2011-02-04")    
sum(!weekdays(seq(Date1, Date2, "days")) %in% c("Saturday", "Sunday"))

編輯:和扎克說,讓那里有Vectorize :)

Dates1 <- as.Date("2011-01-30") + rep(0, 10)
Dates2 <- as.Date("2011-02-04") + seq(0, 9)
Nweekdays <- Vectorize(function(a, b) 
  sum(!weekdays(seq(a, b, "days")) %in% c("Saturday", "Sunday")))
Nweekdays(Dates1, Dates2)

這些修改后的函數考慮了正數或負數的日期差異,而接受的解決方案考慮了正數日期差異。

library("dplyr")

e2 <- structure(list(date.pr = structure(c(16524, 16524, 16524, 16524, 16524, 16524, 16524, 16524, 16524, 16524, 16545, 5974), class = "Date"), 
                     date.po = structure(c(16524, 16525, 16526, 16527, 16528, 16529, 16530, 16531, 16538, 16545, 16524, 15974), class = "Date")), 
                .Names = c("date.1", "date.2"), class = c("tbl_df", "data.frame"), row.names = c(NA, -12L))

1. Locale Dependent Solution: Nweekdays()函數改編自@J。 贏了。解決方案。 它適用於locale = "English_United States.1252"

Nweekdays <- Vectorize(
  function(a, b) 
  {
    ifelse(a < b, 
           return(sum(!weekdays(seq(a, b, "days")) %in% c("Saturday", "Sunday")) - 1), 
           return(sum(!weekdays(seq(b, a, "days")) %in% c("Saturday", "Sunday")) - 1))
  })

一個。 英語區域

> Sys.setlocale(category="LC_ALL", locale = "English_United States.1252")
[1] "LC_COLLATE=English_United States.1252;LC_CTYPE=English_United States.1252;LC_MONETARY=English_United States.1252;LC_NUMERIC=C;LC_TIME=English_United States.1252"

> Sys.getlocale()
[1] "LC_COLLATE=English_United States.1252;LC_CTYPE=English_United States.1252;LC_MONETARY=English_United States.1252;LC_NUMERIC=C;LC_TIME=English_United States.1252"

> e2 %>%
    mutate(wkd1 = format(date.1, "%A"),
           wkd2 = format(date.2, "%A"),
           ndays_with_wkends = ifelse((date.2 > date.1), (date.2 - date.1), (date.1 - date.2)), 
           ndays_no_wkends = Nweekdays(date.1, date.2))

Source: local data frame [12 x 6]

       date.1     date.2   wkd1      wkd2 ndays_with_wkends ndays_no_wkends
       (date)     (date)  (chr)     (chr)             (dbl)           (dbl)
1  2015-03-30 2015-03-30 Monday    Monday                 0               0
2  2015-03-30 2015-03-31 Monday   Tuesday                 1               1
3  2015-03-30 2015-04-01 Monday Wednesday                 2               2
4  2015-03-30 2015-04-02 Monday  Thursday                 3               3
5  2015-03-30 2015-04-03 Monday    Friday                 4               4
6  2015-03-30 2015-04-04 Monday  Saturday                 5               4
7  2015-03-30 2015-04-05 Monday    Sunday                 6               4
8  2015-03-30 2015-04-06 Monday    Monday                 7               5
9  2015-03-30 2015-04-13 Monday    Monday                14              10
10 2015-03-30 2015-04-20 Monday    Monday                21              15
11 2015-04-20 2015-03-30 Monday    Monday                21              15
12 1986-05-11 2013-09-26 Sunday  Thursday             10000            7143

中國區域

> Sys.setlocale(category="LC_ALL", locale = "chinese")
[1] "LC_COLLATE=Chinese (Simplified)_People's Republic of China.936;LC_CTYPE=Chinese (Simplified)_People's Republic of China.936;LC_MONETARY=Chinese (Simplified)_People's Republic of China.936;LC_NUMERIC=C;LC_TIME=Chinese (Simplified)_People's Republic of China.936"

> Sys.getlocale()
[1] "LC_COLLATE=Chinese (Simplified)_People's Republic of China.936;LC_CTYPE=Chinese (Simplified)_People's Republic of China.936;LC_MONETARY=Chinese (Simplified)_People's Republic of China.936;LC_NUMERIC=C;LC_TIME=Chinese (Simplified)_People's Republic of China.936"

> e2 %>%
    mutate(wkd1 = format(date.1, "%A"),
           wkd2 = format(date.2, "%A"),
           ndays_with_wkends = ifelse((date.2 > date.1), (date.2 - date.1), (date.1 - date.2)), 
           ndays_no_wkends = Nweekdays(date.1, date.2))

Source: local data frame [12 x 6]

       date.1     date.2   wkd1   wkd2 ndays_with_wkends ndays_no_wkends
       (date)     (date)  (chr)  (chr)             (dbl)           (dbl)
1  2015-03-30 2015-03-30 ÐÇÆÚÒ» ÐÇÆÚÒ»                 0               0
2  2015-03-30 2015-03-31 ÐÇÆÚÒ» ÐÇÆÚ¶þ                 1               1
3  2015-03-30 2015-04-01 ÐÇÆÚÒ» ÐÇÆÚÈý                 2               2
4  2015-03-30 2015-04-02 ÐÇÆÚÒ» ÐÇÆÚËÄ                 3               3
5  2015-03-30 2015-04-03 ÐÇÆÚÒ» ÐÇÆÚÎå                 4               4
6  2015-03-30 2015-04-04 ÐÇÆÚÒ» ÐÇÆÚÁù                 5               5
7  2015-03-30 2015-04-05 ÐÇÆÚÒ» ÐÇÆÚÈÕ                 6               6
8  2015-03-30 2015-04-06 ÐÇÆÚÒ» ÐÇÆÚÒ»                 7               7
9  2015-03-30 2015-04-13 ÐÇÆÚÒ» ÐÇÆÚÒ»                14              14
10 2015-03-30 2015-04-20 ÐÇÆÚÒ» ÐÇÆÚÒ»                21              21
11 2015-04-20 2015-03-30 ÐÇÆÚÒ» ÐÇÆÚÒ»                21              21
12 1986-05-11 2013-09-26 ÐÇÆÚÈÕ ÐÇÆÚËÄ             10000           10000

2. Locale Independent Solution: Nweekdays()功能改編自@Sacha Epskamp的解決方案。 它適用於所有語言環境,但@Sacha Epskamp使用c(0,6)來清除周末,這與使用c(2,3)提取周末的解決方案不同。

Nweekdays <- Vectorize(
  function(a, b) {
           return(sum(!(((as.numeric(b:a)) %% 7) %in% c(2,3))) - 1) # 2: Saturday and 3: Sunday
  })

一個。 英語區域

> Sys.setlocale(category="LC_ALL", locale = "English_United States.1252")
[1] "LC_COLLATE=English_United States.1252;LC_CTYPE=English_United States.1252;LC_MONETARY=English_United States.1252;LC_NUMERIC=C;LC_TIME=English_United States.1252"

> Sys.getlocale()
[1] "LC_COLLATE=English_United States.1252;LC_CTYPE=English_United States.1252;LC_MONETARY=English_United States.1252;LC_NUMERIC=C;LC_TIME=English_United States.1252"

> e2 %>%
    mutate(wkd1 = format(date.1, "%A"),
           wkd2 = format(date.2, "%A"),
           ndays_with_wkends = ifelse((date.2 > date.1), (date.2 - date.1), (date.1 - date.2)), 
           ndays_no_wkends = Nweekdays(date.1, date.2))

Source: local data frame [12 x 6]

       date.1     date.2   wkd1      wkd2 ndays_with_wkends ndays_no_wkends
       (date)     (date)  (chr)     (chr)             (dbl)           (dbl)
1  2015-03-30 2015-03-30 Monday    Monday                 0               0
2  2015-03-30 2015-03-31 Monday   Tuesday                 1               1
3  2015-03-30 2015-04-01 Monday Wednesday                 2               2
4  2015-03-30 2015-04-02 Monday  Thursday                 3               3
5  2015-03-30 2015-04-03 Monday    Friday                 4               4
6  2015-03-30 2015-04-04 Monday  Saturday                 5               4
7  2015-03-30 2015-04-05 Monday    Sunday                 6               4
8  2015-03-30 2015-04-06 Monday    Monday                 7               5
9  2015-03-30 2015-04-13 Monday    Monday                14              10
10 2015-03-30 2015-04-20 Monday    Monday                21              15
11 2015-04-20 2015-03-30 Monday    Monday                21              15
12 1986-05-11 2013-09-26 Sunday  Thursday             10000            7143

中國區域

> Sys.setlocale(category="LC_ALL", locale = "chinese")
[1] "LC_COLLATE=Chinese (Simplified)_People's Republic of China.936;LC_CTYPE=Chinese (Simplified)_People's Republic of China.936;LC_MONETARY=Chinese (Simplified)_People's Republic of China.936;LC_NUMERIC=C;LC_TIME=Chinese (Simplified)_People's Republic of China.936"

> Sys.getlocale()
[1] "LC_COLLATE=Chinese (Simplified)_People's Republic of China.936;LC_CTYPE=Chinese (Simplified)_People's Republic of China.936;LC_MONETARY=Chinese (Simplified)_People's Republic of China.936;LC_NUMERIC=C;LC_TIME=Chinese (Simplified)_People's Republic of China.936"

> e2 %>%
    mutate(wkd1 = format(date.1, "%A"),
           wkd2 = format(date.2, "%A"),
           ndays_with_wkends = ifelse((date.2 > date.1), (date.2 - date.1), (date.1 - date.2)), 
           ndays_no_wkends = Nweekdays(date.1, date.2))

Source: local data frame [12 x 6]

       date.1     date.2   wkd1   wkd2 ndays_with_wkends ndays_no_wkends
       (date)     (date)  (chr)  (chr)             (dbl)           (dbl)
1  2015-03-30 2015-03-30 ÐÇÆÚÒ» ÐÇÆÚÒ»                 0               0
2  2015-03-30 2015-03-31 ÐÇÆÚÒ» ÐÇÆÚ¶þ                 1               1
3  2015-03-30 2015-04-01 ÐÇÆÚÒ» ÐÇÆÚÈý                 2               2
4  2015-03-30 2015-04-02 ÐÇÆÚÒ» ÐÇÆÚËÄ                 3               3
5  2015-03-30 2015-04-03 ÐÇÆÚÒ» ÐÇÆÚÎå                 4               4
6  2015-03-30 2015-04-04 ÐÇÆÚÒ» ÐÇÆÚÁù                 5               4
7  2015-03-30 2015-04-05 ÐÇÆÚÒ» ÐÇÆÚÈÕ                 6               4
8  2015-03-30 2015-04-06 ÐÇÆÚÒ» ÐÇÆÚÒ»                 7               5
9  2015-03-30 2015-04-13 ÐÇÆÚÒ» ÐÇÆÚÒ»                14              10
10 2015-03-30 2015-04-20 ÐÇÆÚÒ» ÐÇÆÚÒ»                21              15
11 2015-04-20 2015-03-30 ÐÇÆÚÒ» ÐÇÆÚÒ»                21              15
12 1986-05-11 2013-09-26 ÐÇÆÚÈÕ ÐÇÆÚËÄ             10000            7143

我寫了這個,但另一個答案更好:)

Nweekdays <- function(a,b)
{
dates <- as.Date(as.Date(a,"%m/%d/%y",origin="1900-01-01"):as.Date(b,"%m/%d/%y",origin="1900-01-01"),origin="1900-01-01")
days <- format(dates,"%w")[c(-1,-length(dates))]
return(sum(!days%in%c(0,6)))
}

Nweekdays('01/30/2011','02/04/2011')
[1] 3

編輯:計算兩個指定日期之間的工作日數。

編輯:

根據J. Winchesters的建議,該功能可以簡化為:

    Nweekdays <- function(a,b)
{
dates <- as.numeric((as.Date(a,"%m/%d/%y")):(as.Date(b,"%m/%d/%y")))
dates <- dates[- c(1,length(dates))]
return(sum(!dates%%7%in%c(0,6)))
}

一些結果:

> Nweekdays('01/30/2011','02/04/2011')
[1] 4
> 
> Nweekdays('01/30/2011','01/30/2011')
[1] 0
> 
> Nweekdays('01/30/2011','01/25/2011')
[1] 3

請注意,這與區域設置無關。 (關於該主題,我如何更改語言環境?)

我使用以下方法 - 首先是幫手:

weekDays <- function(UPPER = TRUE) {
    days <- c('MONDAY', 'TUESDAY', 'WEDNESDAY',
      'THURSDAY', 'FRIDAY', 'SATURDAY', 
      'SUNDAY')
    if(!UPPER) return(.Internal(tolower(days))) 
    days
}

......現在主要功能:

NumWeekDays <- function(dd, Xdays = c('saturday', 'sunday')) {
    # a function to count the number of non-Xdays in a month
    # >
    # first check if Xdays is of correct format
    stopifnot( all(.Internal(tolower(Xdays)) %in% weekDays(UP = FALSE)))
    # >
    # a helper function to find the number of non-X days between two dates
    NonXDays <- function(startDate, endDate, Xdays) {
        sum(!(.Internal(tolower(weekdays(seq(startDate, endDate, 'day')))) %in% 
              .Internal(tolower(Xdays))))
    }
    startDate <- as.Date(as.yearmon(index(dd)), frac = 0)
    endDate <- as.Date(as.yearmon(index(dd)), frac = 1)
    vapply(1:nrow(dd), 
           FUN = function(i) NonXDays(startDate[i], 
                                      endDate[i], 
                                      Xdays = c('saturday', 'sunday')), 
           FUN.VALUE = numeric(1))
}

例:

set.seed(1)
dx <- apply.monthly(xts(rnorm(600), order.by = Sys.Date() + 1:600), mean)

R> NumWeekDays(dx)
 [1] 23 21 22 23 20 23 22 20 22 22 21 22 23 21 22 22 21 23 21 21

使用lubridate解決這個問題,您可以創建如下函數:

library(lubridate)

WorkingDays_function <- function(StartDate,EndDate){
startDate <- dmy(StartDate)
endDate <- dmy(EndDate)

#Now build a sequence between the dates:
myDates <-seq(from = startDate, to = endDate, by = "days")


#Week starts on Sunday (1) so to exclude Sun (1) and Sat (7)
#use > 1 & < 7  
working_days <- sum(wday(myDates)>1 & wday(myDates)<7)

print(working_days)
}

WorkingDays_function("11/07/2019","20/07/2019") 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM