pandas DataFrame中datetime转epoch秒出现负偏移、分步执行正常的问题排查
pandas时间戳转换出现负值的原因排查
问题描述
我在pandas DataFrame中处理时间戳转换,最初实现代码为:tmp['start'] = tmp['chargingstart'].apply(lambda x: datetime.strptime(x[:19], "%Y-%m-%d %H:%M:%S").timestamp())
我预期得到正整数形式的epoch秒(Unix时间戳),但执行筛选校验代码tmp.loc[(tmp['start']) < 0][['chargingstart', 'start']]后,得到了异常的负值结果。
异常数据示例
chargingstart start 50053 1970-01-01 00:00:48+00 -3552.0 278149 1970-01-01 00:00:17+00 -3583.0 278150 1970-01-01 00:00:16+00 -3584.0 278152 1970-01-01 00:00:17+00 -3583.0 278153 1970-01-01 00:00:17+00 -3583.0 ... ... ... 1590705 1970-01-01 00:00:00+00 -3600.0 1590978 1970-01-01 00:00:00+00 -3600.0 1591012 1970-01-01 00:00:00+00 -3600.0 1702854 1970-01-01 00:00:00+00 -3600.0 1772270 1970-01-01 00:00:00+00 -3600.0
补充验证
我将同一转换逻辑拆分为两步执行,结果显示正常(无负值),分步代码如下:
tmp['convertToDtObject'] = tmp['chargingstart'].apply(lambda x: datetime.strptime(x[:19], "%Y-%m-%d %H:%M:%S")) tmp['start'] = tmp['convertToDtObject'].apply(lambda x: x.timestamp())
问题根因
核心差异来自原生Python datetime对象与pandas Timestamp对象的.timestamp()方法行为不一致:
- 一行代码实现的问题:
datetime.strptime(x[:19], ...)返回的是原生Python的naive datetime对象(无时区信息)- 直接调用该对象的
.timestamp()方法时,Python会强制将这个naive时间解释为本地时区的时间,再转换为UTC对应的epoch秒 - 你截取的是UTC时间字符串的前19位(移除了
+00的时区标识),本地时区与UTC的偏移量(例如UTC+1)会导致计算出的epoch秒为负(例如UTC+1时区下,1970-01-01 00:00:00被解释为本地时间,对应UTC时间为1969-12-31 23:00:00,epoch秒为-3600)
- 拆分两步实现的正常原因:
- 第一步apply返回的原生datetime对象会被pandas自动转换为pandas的
pd.Timestamp对象(pandas datetime列的元素均为pd.Timestamp) - 第二步调用的是
pd.Timestamp的.timestamp()方法,该方法将naive时间直接解释为UTC时间,因此计算结果符合预期
- 第一步apply返回的原生datetime对象会被pandas自动转换为pandas的
可行解决方案
- 若要一行代码实现,可显式指定naive datetime的时区为UTC:
tmp['start'] = tmp['chargingstart'].apply(lambda x: datetime.strptime(x[:19], "%Y-%m-%d %H:%M:%S").replace(tzinfo=pytz.UTC).timestamp()) - 更高效的pandas原生方法(避免apply的循环开销):
tmp['start'] = pd.to_datetime(tmp['chargingstart'].str[:19], utc=True).astype(int) // 10**9
内容的提问来源于stack exchange,提问作者AndreasInfo
相关产品推荐
相关产品推荐

