You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python如何区分混杂多格式日期 转换后实现按时间排序

多格式混杂日期的统一转换与排序方案

问题核心

多格式日期混存时,提前将月份名称替换为数字的操作会抹掉「日字段在月份前/月份后」的位置特征,导致日月顺序错位、转换错误。不需要硬写单一格式的转换规则,利用正则提取阶段保留的格式特征分流处理,配合pandas自带的日期解析能力,即可覆盖所有提到的日期格式。

实现逻辑

通过正则捕获分组提前标记不同日期的格式特征,按类型分别走对应的转换逻辑,最终统一输出为可直接排序运算的datetime类型:

  • 全数字分隔日期(如01/01/1989):直接调用pandas日期解析接口自动识别,可通过dayfirst参数适配不同地区的日期书写习惯
  • 带月份名称的日期:通过捕获的「月份前是否有数字、月份后是否有数字」特征,区分子格式:
    • 月份前有数字:为日 月 年格式(如12 Mar 1989)
    • 月份后有数字:为月 日 年格式(如Mar 12 1989)
    • 月份前后无数字:为月 年格式(如Mar 1989),缺失日字段统一补01
  • 仅标注年份的日期:统一补-01-01,解析为当年1月1日

完整实现代码

import pandas as pd

# 优化正则:用命名分组捕获各格式特征,避免后续靠列位置索引出错
pat1 = r'(?P<num_date>\d{1,2}[/-]\d{1,2}[/-]\d{2,4})' # 匹配全数字分隔日期
pat2 = r'(?P<text_date>(?P<day_before>\d{1,2})?\W?(?P<month>Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[a-z]*\W+(?P<day_after>\d{1,2})?\W?(?P<year>\d{4}))' # 匹配带月份名称的日期,单独捕获月前数字、月份、月后数字、年份
pat3 = r'(?P<year_only>(?<!\d)(\d{4})(?!\d))' # 匹配独立年份
finalpat = f'{pat1}|{pat2}|{pat3}'

# 提取匹配结果,按原索引聚合
df2 = df1.str.extractall(finalpat).groupby(level=0).first()
# 初始化最终解析后的日期列
df2['parse_date'] = pd.NaT

# 1. 处理全数字格式日期
num_date_mask = df2['num_date'].notna()
df2.loc[num_date_mask, 'parse_date'] = pd.to_datetime(
    df2.loc[num_date_mask, 'num_date'],
    dayfirst=False # 如果你的数据以日月年格式为主,将该参数改为True
)

# 2. 处理仅含年份的日期
year_only_mask = df2['year_only'].notna() & ~num_date_mask
df2.loc[year_only_mask, 'parse_date'] = pd.to_datetime(
    df2.loc[year_only_mask, 'year_only'] + '-01-01'
)

# 3. 处理带月份名称的三类日期
text_date_mask = df2['text_date'].notna() & ~num_date_mask & ~year_only_mask
text_sub_df = df2.loc[text_date_mask].copy()
# 月份缩写转数字映射
month_map = {"Jan":'01','Feb':'02','Mar':'03','Apr':'04','May':'05','Jun':'06',
             'Jul':'07','Aug':'08','Sep':'09','Oct':'10','Nov':'11','Dec':'12'}
text_sub_df['month_num'] = text_sub_df['month'].str[:3].map(month_map)

# 3.1 处理 日 月 年 格式
dmy_mask = text_sub_df['day_before'].notna()
dmy_str = (
    text_sub_df.loc[dmy_mask, 'year'] + '-' 
    + text_sub_df.loc[dmy_mask, 'month_num'] + '-' 
    + text_sub_df.loc[dmy_mask, 'day_before'].str.zfill(2)
)
df2.loc[dmy_str.index, 'parse_date'] = pd.to_datetime(dmy_str)

# 3.2 处理 月 日 年 格式
mdy_mask = text_sub_df['day_after'].notna() & ~dmy_mask
mdy_str = (
    text_sub_df.loc[mdy_mask, 'year'] + '-' 
    + text_sub_df.loc[mdy_mask, 'month_num'] + '-' 
    + text_sub_df.loc[mdy_mask, 'day_after'].str.zfill(2)
)
df2.loc[mdy_str.index, 'parse_date'] = pd.to_datetime(mdy_str)

# 3.3 处理 月 年 格式(缺失日补01)
my_mask = ~dmy_mask & ~mdy_mask
my_str = (
    text_sub_df.loc[my_mask, 'year'] + '-' 
    + text_sub_df.loc[my_mask, 'month_num'] + '-01'
)
df2.loc[my_str.index, 'parse_date'] = pd.to_datetime(my_str)

# 最终直接按parse_date列升序排序即可
df_sorted = df2.sort_values('parse_date')

补充说明:对于01/02/1990这类无法从数字本身判断日月顺序的歧义全数字日期,pd.to_datetime会按照dayfirst参数指定的默认规则解析;对于13/02/1990这类月份不可能超过12的明确日期,接口会自动识别格式,不需要额外编写规则。

内容的提问来源于stack exchange,提问作者Marc

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 14:51:17