本地化Pandas Datetime序列存CSV时部分值变为-1的问题求助
问题描述
将本地化到America/Chicago时区的Pandas Datetime序列,尝试通过date_format='%s'参数保存为Unix时间戳格式的CSV时,出现部分Datetime值被保存为-1的异常;不同环境表现不同:
- 在Databricks Runtime 10.4 LTS ML环境(Pandas 1.4/1.2.4、Python 3.8.1)中,保存后读取的CSV里前4行是正确时间戳,后6行均为
-1 - 在Jupyter环境(Pandas 1.2.4、Python 3.8.8)中执行相同代码,直接抛出
ValueError: Invalid format string错误
复现代码如下:
import datetime import pandas as pd df_test = pd.DataFrame({ "Batch ID": [6409713, 6409715, 6409719, 6409721, 6409723, 6409731, 6409733, 6409735, 6409739, 6409741], " SCED Timestamp ": [ datetime.datetime(2022, 3, 13, 1, 40, 17, 999000), datetime.datetime(2022, 3, 13, 1, 45, 19), datetime.datetime(2022, 3, 13, 1, 50, 18), datetime.datetime(2022, 3, 13, 1, 55, 18, 999000), datetime.datetime(2022, 3, 13, 3, 0, 28), datetime.datetime(2022, 3, 13, 3, 5, 20), datetime.datetime(2022, 3, 13, 3, 10, 17, 999000), datetime.datetime(2022, 3, 13, 3, 15, 18), datetime.datetime(2022, 3, 13, 3, 20, 20), datetime.datetime(2022, 3, 13, 3, 25, 18, 999000) ], "Repeated Hour Flag": ['N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N'], "System Lamda": [27.3663, 26.2636, 28.441, 27.1946, 19.4144, 26.5737, 30.4865, 29.5245, 29.6784, 28.6156] }) # 转换为带时区的Datetime索引 datetimes = pd.to_datetime(df_test[' SCED Timestamp ']) datetimes = pd.DatetimeIndex(datetimes) datetimes = datetimes.tz_localize('America/Chicago', ambiguous=(df_test['Repeated Hour Flag'] == 'N')) datetimes.name = "Datetime" df_test = df_test.set_index([datetimes]) # 保存为CSV时出现问题 df_test.index.to_series().to_csv('date_test.csv', date_format='%s') # 读取后部分值为-1 print(pd.read_csv('date_test.csv'))
问题原因
%s格式的兼容性问题:%s是Python标准库strftime的格式符,但Pandas官方并未将其纳入date_format参数的支持范围,其行为依赖底层系统的strftime实现,不同环境的底层库差异会导致报错或返回异常值(如-1)。- 夏令时切换的影响:测试数据中的日期是2022年3月13日,当天是美国中部夏令时切换日(凌晨2点直接跳转为3点),后6个时间点处于切换后的时段,带时区的Datetime在与
%s格式交互时,时区转换逻辑冲突导致异常。 - 旧版Pandas的bug:Pandas 1.2.x/1.4.x版本在处理带时区Datetime的
%s格式时存在缺陷,要么无法识别格式抛出错误,要么错误返回-1。
解决方案
方法1:直接转换为Unix时间戳数值(推荐)
绕过date_format参数,先将带时区的Datetime索引转换为秒级Unix时间戳数值,再保存为CSV,这种方式不依赖底层strftime实现,完全避免时区和格式兼容问题:
# 将带时区的Datetime索引转换为秒级Unix时间戳 timestamp_series = df_test.index.astype('int64') // 10**9 # Pandas Datetime存储为纳秒,除以1e9转秒 timestamp_series.name = "Datetime" # 保存为CSV timestamp_series.to_csv('date_test.csv', header=True) # 读取验证 print(pd.read_csv('date_test.csv'))
方法2:升级Pandas版本
升级到Pandas 1.5.x及以上版本,新版本会明确禁止在带时区Datetime上使用%s格式(直接抛出错误),避免出现静默生成-1的异常情况;但如果需要保存时间戳,方法1依然是更可靠的选择。
方法3:转换为UTC时区后再处理
如果需要保留Datetime格式的操作逻辑,可以先将时区转换为UTC,再使用date_format='%s'(仅适用于不需要保留原时区场景):
# 转换为UTC时区 utc_index = df_test.index.tz_convert('UTC') # 保存为CSV utc_index.to_series().to_csv('date_test.csv', date_format='%s') # 读取验证 print(pd.read_csv('date_test.csv'))
内容的提问来源于stack exchange,提问作者Shahin Shirazi
相关产品推荐
相关产品推荐

