【问题标题】:Convert incomplete 12h datetime-like strings into appropriate datetime type将不完整的 12 小时类日期时间字符串转换为适当的日期时间类型
【发布时间】:2018-12-03 17:12:16
【问题描述】:

我有一个熊猫系列,其中包含 12 小时格式的类似日期时间的字符串,但没有 am/pm 缩写。它涵盖了整个月的数据:

40    01/01/2017 11:51:00
41    01/01/2017 11:51:05
42    01/01/2017 11:55:05
43    01/01/2017 11:55:10
44    01/01/2017 11:59:30
45    01/01/2017 11:59:35
46    02/01/2017 12:00:05
47    02/01/2017 12:00:10
48    02/01/2017 12:13:20
49    02/01/2017 12:13:25
50    02/01/2017 12:24:50
51    02/01/2017 12:24:55
52    02/01/2017 12:33:30
Name: TS, dtype: object
(318621,) # shape

我的目标是将其转换为日期时间格式,以便获得适当的 unix 时间戳值,并与其他日期时间数据进行比较/算术运算,这次是 24 小时格式。所以我已经尝试过了:

pd.to_datetime(df.TS, format = '%d/%m/%Y %I:%M:%S') # %I for 12h format

哪个输出我:

64     2017-01-02 00:46:50
65     2017-01-02 00:46:55
66     2017-01-02 01:01:00
67     2017-01-02 01:01:05
68     2017-01-02 01:05:00

但是上午/下午的信息没有被考虑在内。我知道,作为一项规则,am/pm 首先必须在字符串中指定,然后可以使用 dt.dt.strptime()pd.to_datetime() em> 使用 %p 指示符解析它们。

所以我想知道是否有其他方法可以通过 datetimepandas datetime 模块来处理这个问题?或者,我是否必须在解析之前手动添加缩写“am/pm”?

【问题讨论】:

  • 是否应该一直解析为 PM?
  • @CallCentreExecutive 如果您参考示例中的时间戳,则可以。我说'仍然解析'是因为我认为格式调用中的 %I 会考虑 am/pm 信息,但我知道有 %p 来指示它们。但必须在转换前的str中指定。
  • 那么为什么不给你的日期添加一个“PM”后缀并解析它们呢?
  • @CallCentreExecutive 我可以,但我正在处理一系列 300 000 个日期时间 str (一个月的数据,基本上每 5 秒一个日期时间)。所以我必须编写一个函数来指示何时添加“AM”/“PM”后缀?解析时有没有办法识别?
  • @CallCentreExecutive 我想我误解了你的问题。我的 pandas 系列包含 300 000 个我刚才提到的 12 小时格式的日期时间字符串,每行频率为 5 秒。所以有上午和下午的混合。数据不应总是被解析为 PM。

标签: python-3.x python-datetime


【解决方案1】:

您在多天内以 5 秒的间隔获取数据。所需的结束格式是这样的(我们需要添加 AM/PM 列,因为 Pandas 不可能猜测,因为它一次只查看一个值):

31/12/2016 11:59:55 PM
01/01/2017 12:00:00 AM
01/01/2017 12:00:05 AM
01/01/2017 11:59:55 AM
01/01/2017 12:00:00 PM
01/01/2017 12:59:55 PM
01/01/2017 01:00:00 PM
01/01/2017 01:00:05 PM
01/01/2017 11:59:55 PM
02/01/2017 12:00:00 AM

首先,我们可以在没有 AM/PM 信息的情况下解析整个事情,正如您已经展示的那样:

ts = pd.to_datetime(df.TS, format = '%d/%m/%Y %I:%M:%S')

我们有一个小问题:12:00:00 被解析为中午,而不是午夜。让我们标准化:

ts[ts.dt.hour == 12] -= pd.Timedelta(12, 'h')

现在我们的时间从 00:00:00 到 11:59:55,每天两次。

接下来,请注意转换总是在 00:00:00。我们可以很容易地检测到这些,以及每个日期的第一个实例:

twelve = ts.dt.time == datetime.time(0,0,0)
newdate = ts.dt.date.diff() > pd.Timedelta(0)
midnight = twelve & newdate
noon = twelve & ~newdate

接下来,构建一个偏移序列,应该很容易检查其正确性:

offset = pd.Series(np.nan, ts.index, dtype='timedelta64[ns]')
offset[midnight] = pd.Timedelta(0)
offset[noon] = pd.Timedelta(12, 'h')
offset.fillna(method='ffill', inplace=True)

最后:

ts += offset

【讨论】:

  • 感谢您的回答。就我而言,最初的 .to_datetime() 调用确实将 12:00:00 解析为午夜 00:00:00。所以我不需要标准化步骤。如果相关小时以 '00:mm:ss' 开头,那么 '12' 是一个带有 'True' 的布尔系列吗?还是仅针对特定的“00:00:00”转换?因为在我的系列中,这些转换并不总是在“00:00:00”,例如可能在 00:05:00。并且“newdate”系列仅对与新日期转换对应的行显示“True”?
  • 最终,我理解了您的解决方案。但是,如果所有转换仅是 00:00:00,它就可以工作。我的数据系列中的一些延迟了 5 或 10 秒。
  • @T-DrumY:好的,我想你需要对代码做一些小的调整。例如,您可以设置twelve = (ts.dt.hour == 0) & (ts.dt.minute == 0),然后弄清楚如何仅在每个块中的第一次保持该掩码为真。
猜你喜欢
  • 2014-07-08
  • 2011-05-17
  • 2010-10-01
  • 2020-09-06
  • 2023-04-04
  • 2015-09-17
  • 1970-01-01
  • 2014-11-15
相关资源
最近更新 更多