我想知道是否有人知道如何计算Children.toArray(children).map(func)
中时间戳之间的营业时间或分钟?假设我有两个时间戳:
MATLAB
我想计算started: 22/06/2017 18:00
ended: 26/06/2017 09:00
到08:00
之间的分钟数并排除周末。它应该是17:00
分钟。
有谁知道如何编写600
函数来执行此操作?
我还可以使用MATLAB
和/或python
。
新请求:
如果每个工作日的工作时间更改为R
和9:30-11:30
。我想知道是否有人知道怎么做?
提前致谢!
更新:
@gnovice我对原始代码进行了一些更改。它适用于两个独立范围的使用!不知道你对此感觉如何?
13:00-15:00
答案 0 :(得分:3)
MATLAB解决方案并不像每个人都假设的那样丑陋(尽管可能使用Financial Toolbox进行简化)。为了切入追逐,这里的解决方案是一个接受两个datetime
值的函数:
function workMins = work_time(startTime, endTime)
dateBlock = repmat((dateshift(startTime, 'start', 'day'):...
dateshift(endTime, 'start', 'day')).', 1, 2); %'
dateBlock(:, 1) = dateBlock(:, 1)+hours(8);
dateBlock(:, 2) = dateBlock(:, 2)+hours(17);
dateBlock(1, 1) = max(dateBlock(1, 1), startTime);
dateBlock(end, 2) = min(dateBlock(end, 2), endTime);
dateBlock((datestr(dateBlock(:, 1), 'd') == 'S'), :) = [];
workMins = minutes(sum(max(diff(dateBlock, 1, 2), 0)));
end
以下是一切如何运作......
首先,我们的开始和结束时间为datetime
值:
startTime = datetime('22/06/2017 18:00');
endTime = datetime('26/06/2017 09:00');
现在我们可以创建一个N-by-2
日期时间矩阵。每行都是startTime
到endTime
范围内的一天,时间设置为0:00:00
:
dateBlock = repmat((dateshift(startTime, 'start', 'day'):...
dateshift(endTime, 'start', 'day')).', 1, 2);
现在我们将第一列时间设置为8:00:00
,将第二列时间设置为17:00:00
:
dateBlock(:, 1) = dateBlock(:, 1)+hours(8);
dateBlock(:, 2) = dateBlock(:, 2)+hours(17);
现在我们分别添加startTime
和endTime
作为第一个和最后一个元素,将它们剪切到8:00:00
到17:00:00
时间范围:
dateBlock(1, 1) = max(dateBlock(1, 1), startTime);
dateBlock(end, 2) = min(dateBlock(end, 2), endTime);
接下来,我们删除datestr
天值为'S'
的行(即周末):
dateBlock((datestr(dateBlock(:, 1), 'd') == 'S'), :) = [];
最后,我们采用列差异,求和(忽略负值),并转换为分钟:
workMins = minutes(sum(max(diff(dateBlock, 1, 2), 0)));
我们得到了理想的结果:
workMins =
600
修改强>
关于新请求,您可以稍微更改该功能以允许传递工作日的开始和结束时间,如下所示:
function workMins = work_time(startTime, endTime, workDayStart, workDayEnd)
dateBlock = repmat((dateshift(startTime, 'start', 'day'):...
dateshift(endTime, 'start', 'day')).', 1, 2); %'
dateBlock(:, 1) = dateBlock(:, 1)+hours(workDayStart);
dateBlock(:, 2) = dateBlock(:, 2)+hours(workDayEnd);
...
现在您可以使用单独的工作时间范围调用它并添加结果:
startTime = datetime('22/06/2017 18:00');
endTime = datetime('26/06/2017 09:00');
workTotal = work_time(startTime, endTime, 9.5, 11.5) ...
+ work_time(startTime, endTime, 13, 15);
或从较大范围中减去子范围:
workTotal = work_time(startTime, endTime, 9.5, 15) ...
- work_time(startTime, endTime, 11.5, 13);
如果您希望将工作日时间指定为字符数组,则可以编写如下函数:
function workMins = work_time(startTime, endTime, workDayStart, workDayEnd)
dateBlock = repmat((dateshift(startTime, 'start', 'day'):...
dateshift(endTime, 'start', 'day')).', 1, 2); %'
workDayStart = datevec(workDayStart);
workDayEnd = datevec(workDayEnd);
dateBlock(:, 1) = dateBlock(:, 1)+duration(workDayStart(4:6));
dateBlock(:, 2) = dateBlock(:, 2)+duration(workDayEnd(4:6));
...
并像这样使用它:
workTotal = work_time(startTime, endTime, '9:30', '11:30') ...
+ work_time(startTime, endTime, '13:00', '15:00');
答案 1 :(得分:2)
以下是R
数据强>
start = "22/06/2017 18:00"
end = "26/06/2017 09:00"
<强>功能强>
foo = function(start, end, filter_weekend = TRUE,
daystart = "08:00:00", dayend = "17:00:00", units = "mins"){
#start and end should be POSIXct
require(lubridate)
#Get a sequence of all dates between start and end
df = data.frame(col1 = seq.Date(from = as.Date(start),
to = as.Date(end),
by = "days"))
#Set start of each day at daystart
df$start = ymd_hms(paste(df$col1, daystart))
#Set end of each day at dayend
df$end = ymd_hms(paste(df$col1, dayend))
df$days = weekdays(df$start)
#Set the first day$start to be correct date and time
df$start[1] = start
#Set the last day$end to be correct date and time
df$end[NROW(df)] = end
if (filter_weekend == TRUE){
#Remove weekends
df = df[!df$days %in% c("Saturday", "Sunday"), ]
}
#Remove rows if end is smaller than start (relevant in first and last row)
df = df[df$end > df$start, ]
#Compute time difference for each row
df$time = difftime(time1 = df$end, time2 = df$start, units = units)
#Output
return(sum(df$time))
}
<强> USAGE 强>
library(lubridate)
foo(start = dmy_hm(start), end = dmy_hm(end))
#Time difference of 600 mins
foo(start = dmy_hms("22/06/2017 14:21:19"),
end = dmy_hms("26/06/2017 06:20:53"),
units = "secs", filter_weekend = TRUE)
#Time difference of 41921 secs
答案 2 :(得分:2)
这不是很漂亮,而且必须有一种更为分类的方法,但这应该在基础R中起作用:
x <- seq(from = as.POSIXct("22/06/2017-18:00", format = '%d/%m/%Y-%H:%M'), to = as.POSIXct("26/06/2017-09:00", format = '%d/%m/%Y-%H:%M'), by= (60*60))
x <- x[!weekdays(x) %in% c('Saturday','Sunday')]
x <- x[x %in% as.POSIXct(unlist(lapply(unique(as.Date(x)), function(x){paste0(x, ' ', ifelse(nchar(8:16) == 1, as.character(paste0('0', 8:16)), 8:16))})), format = "%Y-%m-%d %H")]
(length(x)-1)*60
考虑到这一点,用所需的时间跨度生成工作日并将每天的difftime结果加起来可能会更聪明。
答案 3 :(得分:1)
这是一个自定义函数,可用于计算工作分钟数。它有点冗长,但它有一些检查,有助于确保正确计算值。它还将单位作为参数,因此您可以将总数计算为秒,分钟,小时,天或周。
work.time <- function(Date1, Date2, work.start, work.end, unit){
# If dates are equal return 0
if(Date1 == Date2){
return(0)
}
# Check to make sure Date1 is always before Date2
if(Date1 > Date2){
D <- Date1
Date1 <- Date2
Date2 <- D
rm(D)
}
# Get workday start and end timestamps for both days
D1.start <- as.POSIXct(format(Date1, format = paste("%d/%m/%Y", work.start)), format = "%d/%m/%Y %H:%M")
D1.end <- as.POSIXct(format(Date1, format = paste("%d/%m/%Y", work.end)), format = "%d/%m/%Y %H:%M")
D2.start <- as.POSIXct(format(Date2, format = paste("%d/%m/%Y", work.start)), format = "%d/%m/%Y %H:%M")
D2.end <- as.POSIXct(format(Date2, format = paste("%d/%m/%Y", work.end)), format = "%d/%m/%Y %H:%M")
# Calculate value for a full workday
full.day <- as.numeric(difftime(D1.end, D1.start, units = unit))
# Calculate value if dates fall on the same day
if(as.Date(Date1) == as.Date(Date2)){
if(weekdays(as.Date(Date1)) %in% c("Saturday", "Sunday")){
val <- 0
} else if(Date1 >= D1.start & Date2 <= D1.end){
val <- as.numeric(difftime(Date2, Date1, units = unit))
} else if(Date1 >= D1.start & Date2 > D1.end){
val <- as.numeric(difftime(D1.end, Date1, units = unit))
} else if(Date1 < D1.start & Date2 <= D1.end){
val <- as.numeric(difftime(Date2, D1.start, units = unit))
} else if(Date1 < D1.start & Date2 > D1.end){
val <- full.day
} else{
val <- 0
}
return(val)
}
# Calculate value for first workday
if(weekdays(as.Date(Date1)) %in% c("Saturday", "Sunday")){
d1.val <- 0
} else
if(Date1 >= D1.start & Date1 <= D1.end){
d1.val <- as.numeric(difftime(D1.end, Date1, units = unit))
} else if(Date1 > D1.end){
d1.val <- 0
} else if(Date1 < D1.start){
d1.val <- full.day
}
# Calculate value for last workday
if(weekdays(as.Date(Date2)) %in% c("Saturday", "Sunday")){
d2.val <- 0
} else if(Date2 >= D2.start & Date2 <= D2.end){
d2.val <- as.numeric(difftime(Date2, D2.start, units = unit))
} else if(Date2 > D2.end){
d2.val <- full.day
} else if(Date2 < D2.start){
d2.val <- 0
}
# Calculate work value for all workdays between Date1 and Date2
work.days <- sum(!weekdays(seq(as.Date(Date1) + 1, as.Date(Date2) - 1, "days")) %in% c("Saturday", "Sunday"))
# Add up final work value total
work.val <- (work.days * full.day) + d1.val + d2.val
return(work.val)
}
Date1 <- as.POSIXct("24/06/2017 18:00", format = "%d/%m/%Y %H:%M")
Date2 <- as.POSIXct("26/06/2017 09:00", format = "%d/%m/%Y %H:%M")
work.time(Date1, Date2, work.start = "08:00", work.end = "17:00", unit = "mins")