Pandas Timestamp列转datetime.datetime 单行生效整列失效问题
pandas 针对日期时间类型的列默认采用datetime64[ns]存储,该存储格式下所有存入的值都会被自动转换为pandas内置的pandas._libs.tslibs.timestamps.Timestamp类型,哪怕你传入的是Python原生datetime.datetime对象,也会被强制转换,这是框架本身的类型推断机制决定的,不是转换代码逻辑错误。
你遇到的to_sql写入MySQL报错本质是pandas到数据库的类型映射识别偏差,不是必须把整列值手动改成原生datetime格式才能写入。
方案1:写入时显式指定列类型映射(优先选择,零侵入原数据)
不需要修改原DataFrame的任何值,在调用to_sql时通过dtype参数显式指定日期列对应的数据库类型,驱动会自动完成pandas Timestamp到MySQL DATETIME类型的序列化适配,代码如下:
from sqlalchemy import DateTime df.to_sql( name="目标表名", con=你的数据库连接对象, if_exists="append", # 按实际业务需求替换为replace/fail index=False, dtype={ "time": DateTime() } )
该方案是处理同类问题的通用最优解,不会损失datetime类型列的计算性能,90%以上的同类写入报错用该方法可直接解决。
方案2:强制列类型为object保留原生datetime(方案1失效时使用)
如果因为驱动版本过低等问题方案1不生效,可以通过显式指定列dtype为object的方式,阻断pandas的自动类型转换,保证转换后的原生datetime值不被回退为Timestamp,代码如下:
import pandas as pd # 逐元素转换为原生datetime后,以object类型赋值给列 df["time"] = pd.Series( [ts.to_pydatetime() for ts in df["time"]], dtype="object" )
执行后可通过type(df["time"].iloc[0])验证,返回结果为<class 'datetime.datetime'>即转换成功。注意该方案下time列变为object类型,日期相关计算的性能会低于原生datetime64类型,仅作为备选方案使用。
方案3:升级依赖解决版本适配问题
如果以上两个方案都无法解决报错,通常是pandas、SQLAlchemy、MySQL驱动三者的版本兼容问题,直接升级相关依赖到最新稳定版即可:
pip install --upgrade pandas sqlalchemy pymysql
- 不要使用
pd.to_datetime()做转换:该方法的作用就是将输入转换为pandas的datetime64类型,返回值必然是Timestamp,和你要转原生datetime的需求完全相反。 - 不要直接对列使用
apply(lambda x: x.to_pydatetime())赋值:没有指定dtype的情况下,pandas识别到传入值全是datetime对象时,会自动将列转为datetime64类型,把所有值重新转回Timestamp,必须显式指定dtype="object"才能保留转换结果。 - pandas Timestamp本身和MySQL DATETIME类型是兼容的,不需要强行做类型转换,绝大多数写入报错都是类型映射未显式指定导致的,而非值本身的类型问题。
内容的提问来源于stack exchange,提问作者jeremy radcliff

