如何在MATLAB中排除周末之间的时间戳之间的营业时间?

时间:2017-06-23 14:41:15

标签: python r matlab

我想知道是否有人知道如何计算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

新请求
如果每个工作日的工作时间更改为R9:30-11:30。我想知道是否有人知道怎么做?

提前致谢!

更新
@gnovice我对原始代码进行了一些更改。它适用于两个独立范围的使用!不知道你对此感觉如何?

13:00-15:00

4 个答案:

答案 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日期时间矩阵。每行都是startTimeendTime范围内的一天,时间设置为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);

现在我们分别添加startTimeendTime作为第一个和最后一个元素,将它们剪切到8:00:0017: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")