我正在尝试编写一个函数,它将返回两个日期之间的工作日数(不仅仅是排除周末,还包括假日)。我正在接近它,通过构建一个矩阵,其中rownames对应于星期几,矩阵的元素为1或0:如果是假日则为0,或者填充矩阵的额外元素元素。
我已经检查了代码中每个向量的长度。它结账了。我在控制台中手动运行代码,一次一行,它完美地运行。但是,如果我运行该功能,它会显示以下错误消息:
Warning message:
In matrix(da, nrow = 7, dimnames = list(n)) :
data length [132] is not a sub-multiple or multiple of the number of rows [7]
我正在使用R 3.1.1,主要在Rstudio工作。代码中提到的cal
可以找到here。
以下是代码:
dte <- function(date) {
#Input a date and it tells you the number of business (not including holidays)
#days until that date
#Take the target date and turn it into a date
d <- strptime(date,format="%Y-%m-%d")
#Obtain current date
c <- strptime(Sys.Date(), format="%Y-%m-%d")
#Calculate the difference in days
diff <- d-c
#Extract the actual number difference
f <- diff[[1]]
#Get the list of holidays
cal <- dget("cal")
cal <- as.Date(cal)
#Get the full list of dates between now and the target date
b <- Sys.Date()+0:f
#Find which days in the range are holidays
if(any(b %in% cal)) {
bt <- b[b %in% cal]
#Return the position of the holidays within the range
bn <- which(b %in% bt)
} else {
#Set holidays present to 0
bn <- 0
}
#Build a vector of the weekdays starting with the current weekday
n <- weekdays(Sys.Date()+0:6)
#Create a vector as long as the difference with a 1 in each place
v <- rep(1,f)
#Set each holiday to 0
v[bn] <- v[bn]-1
#Extra steps to make sure that the matrix is full but only with 1s where we want them.
g <- ((trunc(f/7)+1)*7)-f
u <- rep(0,g)
da <- c(v,u)
#Create the matrix
m <- matrix(da,nrow=7,dimnames=list(n))
#Extract all of the workweeks and add them up
ww <- m[c("Monday","Tuesday","Wednesday","Thursday","Friday"),]
r <- sum(ww)
r
}
答案 0 :(得分:0)
问题是你的strptime
调用返回了具有时间组件的POSIXt对象,然后受到夏令时的影响。观察
(d1<-strptime("2014-08-24",format="%Y-%m-%d"))
# [1] "2014-08-24 EDT"
(d2<-strptime("2014-12-31",format="%Y-%m-%d"))
# [1] "2014-12-31 EST"
d2-d1
# Time difference of 129.0417 days
因此,这两个值之间没有一定数量的日期会导致您的代码稍后出现问题。如果您使用的是as.Date
而不是strptime
,那么您就不会遇到此问题,因为日期对象并不关心时间。
但我不确定为什么你甚至根本不打扰矩阵。我认为更简单的实现看起来像
dte <- function(date) {
d <- as.Date(date,format="%Y-%m-%d")
c <- Sys.Date()
cal <- dget("cal")
cal <- as.Date(cal)
#Get the full list of dates between now and the target date
b <- seq(c, d, by="1 day")
return(sum(as.POSIXlt(b)$wday %in% 1:5 & (!b %in% cal)))
}