Python读取Excel后日期变数字?数据类型转换与格式化处理方法

小满
小满
发布时间:2026-10-28 | 12人浏览过
原创

详细解析Python使用Pandas或openpyxl读取Excel时日期变为纯数字(如45214)的底层原因,提供基于Excel序列数原理的换算机制、Pandas与原生datetime类型转换步骤、混合脏数据清洗技巧及标准格式化输出方案。

在使用 Python 读取 Excel 文件时,许多开发者会发现原本在表格中显示为“2024-03-15”或“2023/11/02”的日期列,读取到内存中后却变成了诸如 45366 或 45232.5 这样的纯数字。这不是数据损坏,而是 Excel 底层日期存储机制与 Python 读取解析方式不一致导致的常见现象。解决该问题的核心在于:理解 Excel 的“序列数”规则,并在读取时指定解析参数,或在读取后利用 Pandas、openpyxl 等工具将序列号反算回标准时间对象并格式化为目标字符串。

为什么 Excel 中的日期会变成纯数字?

Excel 在底层并不存在独立的“原生日期”存储格式。为了便于计算两个日期之间的间隔天数,Excel 采用了一套名为“序列数”(Serial Number)的连续编号系统。在这套体系中:

  • 整数部分代表日期天数:以 1900 年 1 月 1 日作为基准起点(记为 1),每过去一天,序列号递增 1。例如 2024 年 3 月 15 日距离基准日已经过去了 45366 天,其存储数值就是 45366。
  • 小数部分代表具体时间:一天等于 24 小时(86400 秒),因此中午 12:00:00 对应小数 0.5,下午 18:00:00 对应小数 0.75。例如 45366.5 即代表 2024 年 3 月 15 日 12:00:00。

日常在 Excel 界面上看到的年、月、日格式,实际上只是单元格被赋予了日期显示样式。当使用 Python 工具直接按无格式数值模式读取,或者读取引擎未能识别单元格元数据中的格式代码时,Python 就会直接抓取其底层真实存储的浮点数或整数。

Python读取Excel后日期变数字?数据类型转换与格式化处理方法
图 1:Excel 序列数与 Python 日期时间对象的底层对应与映射机制
注意:为什么基准日是 1899-12-30 而不是 1900-01-01?

历史上早期电子表格软件 Lotus 1-2-3 存在一个著名的设计缺陷:错误地将 1900 年视作闰年(实际上 1900 年不能被 400 整除,是平年,不存在 1900-02-29)。微软 Excel 为了全面兼容 Lotus 1-2-3 的历史数据,刻意保留了这个错误。因此在现代程序转换 Excel 序列号时,起点通常统一向前修正两天,设定为 1899-12-30,以抵消该历史兼容 Bug。

方法一:使用 Pandas 进行转换与格式化

Pandas 是处理表格数据最常用的库。针对读取前后的不同阶段,主要有两种处理途径:

1. 读取时自动解析

如果 Excel 表格格式规范,可以在调用 pd.read_excel 时通过 parse_dates 参数指定需要作为时间解析的列名:

import pandas as pd

# 读取时直接指明日期列
df = pd.read_excel('order_data.xlsx', parse_dates=['订单日期'])

print(df['订单日期'].dtype)  # 输出: datetime64[ns]
print(df['订单日期'].head())

2. 读取后将浮点序列数转为 Datetime

如果读取后日期列依然呈现为数值类型(int64 或 float64),可以使用 pd.to_datetime() 函数进行转换。此时必须传入 unit='D' 和修正基准起点 origin='1899-12-30':

import pandas as pd

df = pd.read_excel('order_data.xlsx')

# 将 Excel 序列数转换为 Pandas 标准 Timestamp
df['处理后日期'] = pd.to_datetime(df['订单日期'], unit='D', origin='1899-12-30')

# 格式化输出为 YYYY-MM-DD 文本
df['日期文本'] = df['处理后日期'].dt.strftime('%Y-%m-%d')

# 若包含时间,可输出完整时分秒
df['完整时间文本'] = df['处理后日期'].dt.strftime('%Y-%m-%d %H:%M:%S')

print(df[['订单日期', '处理后日期', '日期文本']].head())
Python读取Excel后日期变数字?数据类型转换与格式化处理方法
图 2:基于 Pandas 的日期类型转换与格式化标准步骤

方法二:使用 openpyxl 逐格读取与原生转换

如果任务需求不需要引入完整的 Pandas 库,或者需要精确操作 Excel 单元格属性,可直接使用 openpyxl 以及 Python 原生 datetime 模块。

openpyxl 默认具备自动识别单元格日期格式的能力,当其检测到日期样式时,cell.value 会直接返回 datetime.date 或 datetime.datetime 对象。但如果该单元格的格式曾被手动清除或设置为“常规”,读取结果就会退化为整数或浮点数:

from datetime import datetime, timedelta
import openpyxl

# 加载工作簿
wb = openpyxl.load_workbook('order_data.xlsx', data_only=True)
ws = wb.active

# Excel 修正基准日
excel_origin = datetime(1899, 12, 30)

for row in ws.iter_rows(min_row=2, max_col=1, values_only=False):
    cell = row[0]
    val = cell.value

    if val is None:
        continue

    # 1. 单元格元数据已被识别为日期
    if cell.is_date:
        parsed_date = val
    # 2. 单元格格式丢失,表现为整数或浮点数
    elif isinstance(val, (int, float)):
        parsed_date = excel_origin + timedelta(days=val)
    # 3. 单元格已经是字符串格式
    elif isinstance(val, str):
        parsed_date = datetime.strptime(val.strip(), '%Y-%m-%d')
    else:
        parsed_date = None

    if parsed_date:
        # 输出标准化格式字符串
        formatted_str = parsed_date.strftime('%Y-%m-%d %H:%M:%S')
        print(f"单元格坐标 {cell.coordinate}: 原始值 {val} -> 格式化结果 {formatted_str}")

进阶场景:混合“脏数据”列的清洗方案

在实际业务报表中,经常出现最棘手的情况:同一列数据中,一部分是 Excel 序列数字(45366),一部分是手工录入的文本日期('2024-03-15' 或 '2024/03/15'),同时混杂着缺失值(NaN)。如果直接调用单一转换规则,必定会出现报错或转换失败。

此时可以使用“分别转换、优先级合并”的清洗策略:

Python读取Excel后日期变数字?数据类型转换与格式化处理方法
图 3:针对数字与文本混杂列的双轨清洗决策流

对应的 Pandas 实现代码如下:

import pandas as pd

# 模拟含有数字、字符串以及缺失值的混合列
raw_data = {'混合日期': [45366, '2024-03-16', 45368.5, '2024/03/18', None, '无效文本']}
df = pd.DataFrame(raw_data)

# 1. 尝试按数字处理:非数字强制转为 NaN,再用 Excel 原点还原
num_series = pd.to_numeric(df['混合日期'], errors='coerce')
dates_from_num = pd.to_datetime(num_series, unit='D', origin='1899-12-30')

# 2. 尝试按字符串处理:非有效日期文本强制转为 NaN
dates_from_str = pd.to_datetime(df['混合日期'], errors='coerce')

# 3. 优先级合并:以数字解析为主,若为空则由文本解析结果补齐
df['规范日期'] = dates_from_num.combine_first(dates_from_str)

# 4. 格式化输出目标字符串
df['最终显示'] = df['规范日期'].dt.strftime('%Y-%m-%d %H:%M:%S').fillna('空缺或异常')

print(df[['混合日期', '规范日期', '最终显示']])

方案对比与排查速查

为了在实际开发中快速选用最合适的技术方案,下表总结了各种处理方式的适用场景及核心代码:

处理方案 适用场景 核心参数 / 方法 输出类型
Pandas read_excel Excel 文件规范、需直接批量读取 parse_dates=['列名'] datetime64[ns]
Pandas to_datetime 已读入内存且呈现为纯数字序列号 unit='D', origin='1899-12-30' datetime64[ns]
openpyxl 单元格判断 不需要安装 Pandas,轻量或需操作单元格格式 cell.is_date 与 timedelta(days=val) datetime.datetime
双轨清洗 (combine_first) 历史填报混乱,文本、序列号混杂 to_numeric + combine_first 清洗后的标准列
Python读取Excel后日期变数字?数据类型转换与格式化处理方法
图 4:三大主流处理路径的特征、适用场景与最佳实践总结

结语与注意事项

当在 Python 中遇到 Excel 日期变成五位数字时,切勿将其作为普通数值或随意截断文本。只要牢记 Excel 的 1899-12-30 序列基准,通过 Pandas 的 pd.to_datetime(col, unit='D', origin='1899-12-30') 即可精准还原时间对象。在最终持久化或对外导出报表时,调用 .dt.strftime('%Y-%m-%d') 转化为统一格式字符串,便能保证下游数据库和业务接口的数据准确性。

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表