【问题标题】:Pandas calculate the time difference in seconds excluding business daysPandas 以秒为单位计算时差,不包括工作日
【发布时间】:2021-08-25 14:50:05
【问题描述】:

我有一个包含两列的数据集。一个是Message Received Timestamp,另一个是Message Sent Timestamp。时间的格式看起来像这样2021-06-05T07:00:34Z。我想计算这两列之间的时间差(以秒为单位),并通过排除工作日来确保差小于24 hours

我知道np.busday_count 方法,但我想以秒为单位计算差异。请在下面查看我当前的代码,它没有考虑工作日:(pd.to_datetime(df["Message Received Timestamp"]) - pd.to_datetime(df["Message Sent Timestamp"])) < pd.Timedelta("1 day")

非常感谢您在计算工作日(以秒为单位)时提供的帮助。非常感谢。

【问题讨论】:

  • 这很容易做到...手动解析值并编写自己的输出函数
  • @Tartempion 感谢您的建议,但您能否介意通过解析值来澄清
  • 对不起,我看错了……
  • @Tartempion 我想知道您是否可以澄清“解析值”的意思
  • 我最初的意思是处理字符串以获取日期和小时值,但 pd.to_datetime 似乎适用于您的格式

标签: python pandas numpy time


【解决方案1】:

我会做这样的事情......不过不要认为这是理所当然的,在某些特定情况下它可能是错误的。

import numpy as np
import pandas as pd

# test dates
date1 = '2021-03-05T07:00:34Z'
date2 = '2021-10-04T11:41:01Z'

d1 = pd.to_datetime(date1)
d2 = pd.to_datetime(date2)

# business days delta
bus_days_delta = (d2 - d1).days - np.busday_count(date1.partition("T")[0], date2.partition("T")[0])
date2real = d2 - pd.to_timedelta(bus_days_delta, unit='d')

# business day delta in seconds
real_delta = date2real - pd.to_datetime(date1)
print(real_delta)

【讨论】:

  • 我当前的代码没有考虑工作日,我必须在时差计算中考虑工作日。目标是通过排除工作日来确保以秒为单位的时差小于 24 小时。
  • 这对我来说似乎很奇怪和/或复杂。工作日因国家/地区而异(例如,在法国,5 月 1 日是一个工作日),因此您发现针对特定案例实施工作日的机会受到限制...
  • 但如果您真的想这样做,我会存储一个工作日列表并将其排除在我的比较之外(不知何故?)
  • 您说得对,工作日因国家/地区而异。但是对于 np.busday_count 的 numpy 函数,你知道我们是否可以按秒计算吗?
  • 非常感谢,但如果我尝试使用以下两个值date1 = '2021-06-04T07:00:34Z'date2 = '2021-06-07T06:41:01Z',它会给我一个1 days 23:40:27 的答案。如果我们不包括周末,我认为这两个日期之间的差异应该小于一天
【解决方案2】:

您可以使用Timedelta.total_seconds() 获取两个日期之间的总时间差(以秒为单位),如下所示:

df["Diff_Total_Seconds"] = (pd.to_datetime(df["Message Received Timestamp"]) - pd.to_datetime(df["Message Sent Timestamp"])).dt.total_seconds() 

然后通过将np.busday_count 乘以 86400(一天中的秒数)来计算工作日的总秒数:

df["Busday_Total_Seconds"] = (np.busday_count(pd.to_datetime(df["Message Sent Timestamp"]).values.astype('datetime64[D]'), pd.to_datetime(df["Message Received Timestamp"]).values.astype('datetime64[D]')) - 1) * 86400

最后,得到不包括工作日的时差,以秒为单位。

df["Diff_Total_Seconds_Excl_Busday"] = df["Diff_Total_Seconds"] - df["Busday_Total_Seconds"] 

测试结果:

  Message Received Timestamp Message Sent Timestamp  Diff_Total_Seconds  Busday_Total_Seconds  Diff_Total_Seconds_Excl_Busday
0       2021-06-07T06:41:01Z   2021-06-04T07:00:34Z            258027.0                     0                        258027.0
1       2021-06-09T06:41:01Z   2021-06-08T07:00:34Z             85227.0                     0                         85227.0

编辑

在与 OP 进一步讨论后,我们提出了一些特殊情况的更新代码。

df["Message Received Timestamp"] = pd.to_datetime(df["Message Received Timestamp"])
df["Message Sent Timestamp"] = pd.to_datetime(df["Message Sent Timestamp"])
df["Diff_Total_Sec"] = (df["Message Received Timestamp"] - df["Message Sent Timestamp"]).dt.total_seconds()
df["Diff_Days"] = (df["Message Received Timestamp"].dt.normalize() - df["Message Sent Timestamp"].dt.normalize()).dt.days
df["NonBDay_Total_Sec"] = (df["Diff_Days"] - np.busday_count(df["Message Sent Timestamp"].values.astype('datetime64[D]'), df["Message Received Timestamp"].values.astype('datetime64[D]'))) * 86400
df["NonBDay_Total_Sec"] = np.where((df["Message Received Timestamp"].dt.dayofweek == 6) & (df["NonBDay_Total_Sec"] < 86400 * 2), 86400 * 2, df["NonBDay_Total_Sec"])
df["NonBDay_Total_Sec"] = np.where((df["Message Received Timestamp"].dt.dayofweek == 5) & (df["NonBDay_Total_Sec"] < 86400), 86400, df["NonBDay_Total_Sec"])
df["Diff_Total_Sec_Excl_NonBDay"] = df["Diff_Total_Sec"] - df["NonBDay_Total_Sec"] 
df["Validity_Result"] = (df["Diff_Total_Sec_Excl_NonBDay"] < 86400) & (df["Message Sent Timestamp"] <= df["Message Received Timestamp"])

测试结果:

   Message Received Timestamp    Message Sent Timestamp  Diff_Total_Sec  Diff_Days  NonBDay_Total_Sec  Diff_Total_Sec_Excl_NonBDay  Validity_Result
0   2021-06-07 06:41:01+00:00 2021-06-04 07:00:34+00:00        258027.0          3             172800                      85227.0             True
1   2021-06-07 06:41:01+00:00 2021-06-07 05:41:01+00:00          3600.0          0                  0                       3600.0             True
2   2021-06-07 06:41:01+00:00 2021-06-07 07:41:01+00:00         -3600.0          0                  0                      -3600.0            False
3   2021-06-07 06:41:01+00:00 2021-06-03 06:41:01+00:00        345600.0          4             172800                     172800.0            False
4   2021-06-07 06:41:01+00:00 2021-06-10 06:41:01+00:00       -259200.0         -3                  0                    -259200.0            False
5   2021-06-07 06:41:01+00:00 2021-06-03 07:00:01+00:00        344460.0          4             172800                     171660.0            False
6   2021-06-07 06:41:01+00:00 2021-06-04 07:00:01+00:00        258060.0          3             172800                      85260.0             True
7   2021-06-07 06:41:01+00:00 2021-06-04 05:00:01+00:00        265260.0          3             172800                      92460.0            False
8   2021-06-06 22:01:03+00:00 2021-06-04 09:38:38+00:00        217345.0          2             172800                      44545.0             True
9   2021-06-05 07:01:36+00:00 2021-06-04 03:49:42+00:00         97914.0          1              86400                      11514.0             True
10  2021-06-07 01:10:09+00:00 2021-06-03 03:32:06+00:00        337083.0          4             172800                     164283.0            False
11  2021-06-06 09:03:34+00:00 2021-06-04 08:36:36+00:00        174418.0          2             172800                       1618.0             True

【讨论】:

  • 非常感谢您的建议,但由于某些原因,我会收到此错误TypeError: Iterator operand 0 dtype could not be cast from dtype('&lt;M8[ns]') to dtype('&lt;M8[D]') according to the rule 'safe'
  • @SkipperLin 哪一行代码得到了错误信息?
  • 如果我直接运行第二行会出现这个错误Could not convert object to NumPy datetime。所以我将第二行更新为df["Busday_Total_Seconds"] = np.busday_count(pd.to_datetime(df["Message Received Timestamp"]), pd.to_datetime(df["Execution Timestamp"])),我会在之前的评论中看到错误
  • @SkipperLin 您的时间戳列可能是字符串,而不是 datetime64 格式。好的,让我再检查一下第二行。
  • 非常感谢!是的,原始格式是字符串,需要额外的转换。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-03
  • 2014-02-06
  • 1970-01-01
相关资源
最近更新 更多