如何阻止Pandas将Python datetime转换为datetime64[ns]以导出兼容Azure Data Factory的Parquet文件
首先得明确一点:Pandas本身没法在DataFrame中直接保留原生datetime.datetime类型的列。这是Pandas的设计决定——它依赖NumPy的datetime64[ns]类型实现时间序列的高效存储和运算,只要你把原生datetime对象放入Series/DataFrame,Pandas就会自动将其转换为datetime64[ns]类型,哪怕用apply逐个转换后赋值回去也一样,这是内置的类型优化逻辑,没法绕过。
不过你的核心需求是让Azure Data Factory(ADF)能正确读取Parquet中的时间列,所以不用纠结在DataFrame里保留原生datetime,而是要从Parquet文件的导出格式入手,让导出的时间类型符合ADF的识别要求。
推荐方案:用PyArrow引擎导出标准Parquet TIMESTAMP类型
ADF对Parquet的标准TIMESTAMP类型支持更好,而Pandas默认导出的时间格式(依赖int96时间戳)可能导致识别问题。我们可以用PyArrow引擎指定导出标准的TIMESTAMP类型:
- 先安装PyArrow依赖:
pip install pyarrow
- 导出Parquet时指定引擎并关闭int96时间戳:
import pandas as pd # 假设你的DataFrame是df df.to_parquet( "your_output_file.parquet", engine="pyarrow", use_deprecated_int96_timestamps=False # 禁用int96,使用标准TIMESTAMP类型 )
这样导出的Parquet文件中,时间列会以Parquet标准的TIMESTAMP格式存储,ADF就能正确识别了。
备选方案:将时间列存为Object类型(不推荐,仅作参考)
如果你一定要在DataFrame中保留原生datetime对象(虽然对后续处理没太大必要),可以强制将列转为object类型:
# 将时间列转换为原生datetime并存为object类型 df["native_datetime"] = df["timestamp"].apply(lambda x: x.to_pydatetime()).astype("object") # 验证类型 print(df.dtypes["native_datetime"]) # 输出 object print(type(df["native_datetime"][0])) # 输出 <class 'datetime.datetime'>
但要注意:
- Object类型的列会失去Pandas时间序列的所有高效运算能力
- 导出Parquet时,PyArrow会将object类型中的datetime序列转为标准TIMESTAMP类型,而fastparquet可能会转为字符串,反而更麻烦,所以还是优先推荐第一种方案。
为什么Pandas会自动转换类型?
Pandas的设计目标是高效处理大规模数据,原生Python datetime.datetime对象是不可变的Python对象,存储和运算效率远低于NumPy的datetime64[ns](后者是基于数值的向量类型)。因此Pandas会自动将原生datetime转换为datetime64[ns],这是内置的优化逻辑,没有办法直接禁用。
内容的提问来源于stack exchange,提问作者Mike Williamson

