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

Pandas将日期差数值转换为精确到天的年月日可读文本格式

Pandas 计算日期间隔并转年/月/日文本格式

问题背景

现有客户购买记录DataFrame结构如下:

cust_id,purchase_date
   1,10/01/1998
   1,10/12/1999
   2,13/05/2016
   3,14/02/2018
   3,15/03/2019

原有实现代码直接用固定365天做除法,输出十进制小数的间隔值,不符合要求:

from datetime import timedelta
df['purchase_date'] = pd.to_datetime(df['purchase_date'])
gb = df_new.groupby(['unique_key'])
df_cust_age = gb['purchase_date'].agg(min_date=np.min, max_date=np.max).reset_index()
df_cust_age['diff_in_days'] = df_cust_age['max_date'] - df_cust_age['min_date']
df_cust_age['years_diff'] = df_cust_age['diff_in_days']/timedelta(days=365)

需求明细

  • 按客户ID分组,计算每个客户最早、最晚购买日期的间隔
  • 时间差禁止输出十进制小数,需转换为精确到天的年、月、日拼接文本格式
  • 自动匹配单复数单位(数值为1时用单数单位year/month/day,其余情况用复数单位)
  • 目标输出效果:
cust_id,years_diff
  1, 1 years and 11 months and 0 day
  2, 0 years
  3, 1 year and 1 month and 1 day

实现方案

使用dateutil.relativedelta按自然年月计算精确间隔,自定义格式化函数处理单复数和拼接逻辑:

import pandas as pd
import numpy as np
from dateutil.relativedelta import relativedelta

# 1. 加载并解析日期,注意原始日期为日/月/年格式,需指定dayfirst避免解析错误
df = pd.DataFrame({
    'cust_id': [1,1,2,3,3],
    'purchase_date': ['10/01/1998','10/12/1999','13/05/2016','14/02/2018','15/03/2019']
})
df['purchase_date'] = pd.to_datetime(df['purchase_date'], dayfirst=True)

# 2. 分组计算每个客户的最早、最晚购买日期
df_cust_age = df.groupby('cust_id')['purchase_date'].agg(
    min_date=np.min,
    max_date=np.max
).reset_index()

# 3. 定义时间差格式化函数
def format_date_gap(start_date, end_date):
    gap = relativedelta(end_date, start_date)
    text_parts = []
    # 拼接年部分
    if gap.years:
        unit = 'year' if gap.years == 1 else 'years'
        text_parts.append(f"{gap.years} {unit}")
    # 拼接月部分
    if gap.months:
        unit = 'month' if gap.months == 1 else 'months'
        text_parts.append(f"{gap.months} {unit}")
    # 拼接日部分
    if gap.days:
        unit = 'day' if gap.days == 1 else 'days'
        text_parts.append(f"{gap.days} {unit}")
    # 处理无间隔(仅1条购买记录)的情况
    if not text_parts:
        return "0 years"
    # 用and拼接各部分
    return ' and '.join(text_parts)

# 4. 生成最终格式列
df_cust_age['years_diff'] = df_cust_age.apply(
    lambda row: format_date_gap(row['min_date'], row['max_date']),
    axis=1
)

# 提取结果列
result = df_cust_age[['cust_id', 'years_diff']]
print(result)

运行结果

cust_id                     years_diff
0        1  1 year and 11 months and 0 day
1        2                         0 years
2        3    1 year and 1 month and 1 day

说明:相比固定按365天折算年的方式,relativedelta按自然日历规则计算间隔,不会出现闰年、大小月导致的计算偏差。如果需要严格匹配示例里1 years的写法,只需修改单复数判断逻辑即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 02:33:27