报错是这么冒出来的。pandas 2.2 在 Windows 上读一份供应商导出的 xlsx,日期列读出来是 45000 这样的整数,写进 PostgreSQL 后全变成 1900 年。用 Excel 打开显示的是 2023-03-15,同一份文件另存成 csv 再读又是对的,说明问题在读取这一层。

中间走过弯路,把「文件来自第三方导出,日期列没有真正的日期类型」当成主因,改完现象没变。

原因不止一个,得分开看。单元格本身是数字格式,只是显示层套了日期样式。也可能是openpyxl 按值读取,拿到的是序列号不是 datetime。

少数情况下是read_excel 指定了 dtype,把日期强行转成了整型。

先看这一列的原始类型和几个样本值

python -c "import pandas as pd;df=pd.read_excel('supplier.xlsx');print(df['日期'].dtype, df['日期'].head())"

然后按 1899-12-30 起点把序列号转成日期

python -c "import pandas as pd;df=pd.read_excel('supplier.xlsx');df['日期']=pd.to_datetime(df['日期'],unit='D',origin='1899-12-30');print(df['日期'].head())"

入库前统一成 ISO 字符串,避免驱动再猜一次类型

python -c "import pandas as pd;df=pd.read_excel('supplier.xlsx');print(df.assign(d=pd.to_datetime(df['日期'],unit='D',origin='1899-12-30').dt.strftime('%Y-%m-%d')).head())"

等前面都确认过,再把转换写进读取函数,后续文件复用同一个入口

python load_excel.py --file supplier.xlsx --date-cols 日期 --serial-origin 1899-12-30

恢复的判定其实很直接。转换后的列 dtype 是 datetime64,入库的值与 Excel 里显示的日期逐行一致,1900 年附近的脏值不再出现。

这里还有个坑。1900 年 2 月 29 日那个历史 bug 会让序列号在 60 附近偏移一天,跨百年的老数据要单独校验。改动前把原配置备份一份,出问题能马上回滚,这比任何技巧都实用。

作者 9823189