如何在工作时间内获得总小时数?

How to get total hours during working hours?

我在 pandas 中有两列是 UTC 时间戳:StartDateEndDate。这些日期适用于提交寻求帮助的任务。我正在尝试计算这些任务在工作时间内完成之前存在了多少小时。我公司的营业时间为太平洋标准时间周一至周五上午 8 点至下午 6 点。

我已经尝试进行这些计算,但 运行 遇到了问题。我不知道如何只在工作时间获得时间。我已经想出如何在整个时间段内计算时间,但我不知道如何继续进行。我目前的想法是在 for 循环中制作一个 if 语句并检查从我的计算中生成的 SLATable['Date Responded (Hours)'] 列的每个值,但上次我尝试编辑值时单独在列中 python 抛出我一个错误。

#8-6 PST to UTC time
officeOpen = pd.Timestamp("8:00:00.000").tz_localize('US/Pacific').tz_convert('utc')
officeClose = pd.Timestamp("18:00:00.000").tz_localize('US/Pacific').tz_convert('utc')

#get data from sql server
SLATable = pd.read_sql_query(SqlQuery,conn)

#calculate Date Responded
SLATable['Date Responded (Hours)'] = SLATable['EndDate'] - SLATable['StartDate']
SLATable['Date Responded (Hours)'] = round(SLATable['Date Responded (Hours)']/np.timedelta64(1,'h'), 2)

目前,如果我使用上面的代码,如果它是在工作时间创建的,那么它适用于在创建当天完成的任何任务,但周一创建并在周二完成的任务将在工作时间之外工作工作时间。此外,如果任务是在办公时间以外创建的,它将收集时间,直到我们在工作时间内解决它。

这些计算不适用于周一至周五 8 点到 6 点的任何国家/地区的假期。

示例数据如果 运行 通过我的计算:

StartDate       EndDate       Date Responded (Hours)
2016-05-03      2016-05-03    0.13
15:51:11.850    15:59:13.017

2016-05-05      2016-05-06    17.64
23:01:51.023    16:40:21.350

如果计算正确,输出应该是什么:

StartDate       EndDate       Date Responded (Hours)
2016-05-03      2016-05-03    0.13
15:51:11.850    15:59:13.017

2016-05-05      2016-05-06    0.32
23:01:51.023    16:40:21.350

第一步是定义一个 BusinessHour 偏移量,使用适当的 开始/结束时间(稍后会用到):

bhOffs = pd.offsets.BusinessHour(start='08:00', end='18:00')

然后定义一个从 UTC 时间计算业务时间的函数,使用 正确的时区偏移量:

def BusTime(ts, hOffs, fwd):
    '''Compute business time. Params:
    ts    - UTC time (string or Timestamp)
    hOffs - Hour offset (int)
    fwd   - Roll variant (forward / backward, bool)
    '''
    tsWrk = ts if type(ts) == 'str' else pd.Timestamp(ts)
    tsOffs = tsWrk + np.timedelta64(hOffs, 'h')
    if fwd:  # Roll if on End of Day
        tsRoll = bhOffs.rollforward(tsOffs + np.timedelta64(1, 'ms'))
    else:    # Don't roll if on End of Day
        tsRoll = bhOffs.rollforward(tsOffs - np.timedelta64(1, 'ms'))
    return tsRoll if tsRoll.day != tsOffs.day else tsOffs

最后一步,定义一个计算营业时间的函数:

def BusHrs(ts1, ts2, hOffs=0):
    '''Compute business hours between 2 DateTimes. Params:
    ts1, ts2 - From / To (UTC, Timestamp or string)
    hOffs    - Hour offset (int)
    '''
    t1 = BusTime(ts1, hOffs, True)
    t2 = BusTime(ts2, hOffs, False)
    bHrs = pd.date_range(start=t1.floor('h'), end=t2.floor('h'),
        freq=bhOffs, closed='left').size
    frac1 = t1 - t1.normalize() - np.timedelta64(t1.hour, 'h')
    frac2 = t2 - t2.normalize() - np.timedelta64(t2.hour, 'h')
    return bHrs + (frac2 - frac1) / np.timedelta64(1, 'h')

想法是:

  • 将 UTC 开始/结束时间转换为正确的时区。
  • 在本地开始/结束时间之间生成一个 DatetimeIndex, 四舍五入为整小时。
  • 从该索引的大小中获取完整小时数。
  • 从开始/结束时间按小时的小数部分更正。

我对你的数据进行了测试:

  • BusHrs('2016-05-03 15:51:11.850', '2016-05-03 15:59:13.017', -7) - 结果 0.1336575.
  • BusHrs('2016-05-05 23:01:51.023', '2016-05-06 16:40:21.350', -7) - 结果 3.6417574999999998.

第二个结果和你预期的结果不一样,但是原理 如下:

  • 开始时间:2016-05-05 23:01 UTC 是 2016-05-05 16:01(太平洋时间)。
  • 结束时间:2016-05-06 16:40 UTC 是 2016-05-06 09:40(太平洋)。
  • 2016-05-05 的工作时间差不多 2 小时(最多 18:00)。
  • 2016-05-06 的工作时间差不多 1 小时 40 米(来自 8:00)。
  • 两个工作时间的总和只是 3.64....

我没有在你的第三组开始/结束时间测试这个功能,因为 估计是哪里出了问题(实际工作时间远远超过 您的预期结果)。