还在Excel里手动拆分日期、计算间隔?Python让你一键搞定所有日期时间操作!
一、先看这个真实场景
周主任每个月都要做这些事:
- 从考勤系统导出打卡记录(几千行,日期格式乱七八糟)
以前他用Excel:
- 计算工龄 → DATEDIF函数 → 还要考虑闰年 ✓
一天又没了!
二、Python的“时间旅行”魔法
今天教你用Pandas处理日期时间,三行代码搞定上面所有事:
import pandas as pd# 模拟考勤数据(日期是字符串)df = pd.DataFrame({'姓名': ['张三', '李四', '王五', '赵六'],'打卡日期': ['2023-05-12', '2023/6/3', '2023.07.18', '2023-08-25'],'入职日期': ['2018-03-15', '2020-07-01', '2019-11-20', '2021-12-10']})# 魔法开始!统一转换为时间类型df['打卡日期'] = pd.to_datetime(df['打卡日期'])df['入职日期'] = pd.to_datetime(df['入职日期'])# 提取年份、月份、星期、季度df['打卡年份'] = df['打卡日期'].dt.yeardf['打卡月份'] = df['打卡日期'].dt.monthdf['星期几'] = df['打卡日期'].dt.day_name()df['季度'] = df['打卡日期'].dt.quarter# 计算工龄(到今天的天数)df['工龄(天)'] = (pd.Timestamp.now() - df['入职日期']).dt.daysprint("✅ 一键转换完成:")print(df[['姓名', '打卡日期', '打卡年份', '打卡月份', '星期几', '季度', '工龄(天)']])
看懂了吗?
- pd.to_datetime():把乱七八糟的日期字符串统一转成Pandas时间类型
- .dt.year/.month/.day/.day_name()/.quarter:像变魔术一样提取各种时间成分
- 时间相减:直接得到时间间隔,再用.dt.days取天数
三、分解“魔法”:每步在干什么?
3.1 第一步:统一日期格式
df['打卡日期'] = pd.to_datetime(df['打卡日期'])
输入可以是:
'2023-05-12'、'2023/6/3'、'2023.07.18'、'12-May-2023'……
输出:
统一变成Pandas的Timestamp类型,显示为2023-05-12这样的标准格式。
如果遇到无法解析的日期,可以加参数errors='coerce',将无效日期转为NaT(缺失时间)。
3.2 第二步:提取时间成分
df['打卡年份'] = df['打卡日期'].dt.yeardf['打卡月份'] = df['打卡日期'].dt.monthdf['打卡日'] = df['打卡日期'].dt.daydf['星期几'] = df['打卡日期'].dt.day_name() # 英文星期df['星期几中文'] = df['打卡日期'].dt.day_name(locale='zh_CN') # 中文星期(需安装babel)df['季度'] = df['打卡日期'].dt.quarterdf['第几周'] = df['打卡日期'].dt.isocalendar().week # 一年中的第几周
常用属性:
- .year, .month, .day:年、月、日
- .hour, .minute, .second:时、分、秒(如果有时间)
- .dayofweek:星期几(0=周一,6=周日)
- .day_name():星期名称(Monday等)
- .isocalendar().week:ISO周数
3.3 第三步:时间运算
# 计算两个日期的间隔df['入职天数'] = (df['打卡日期'] - df['入职日期']).dt.days# 计算年龄(假设今天是2024-01-01)今天 = pd.Timestamp('2024-01-01')df['年龄'] = (今天 - df['入职日期']).dt.days // 365 # 粗略# 更精确的年龄(考虑月份)df['年龄精确'] = (今天 - df['入职日期']).astype('timedelta64[Y]') # 浮点数年
注意:时间相减得到的是Timedelta对象,可以用.dt.days取天数,.dt.seconds取秒数。
3.4 第四步:筛选特定时间范围
# 筛选2023年5月的数据df_5月 = df[df['打卡日期'].dt.month == 5]# 筛选2023年第二季度df_Q2 = df[(df['打卡日期'].dt.quarter == 2) & (df['打卡日期'].dt.year == 2023)]# 筛选本周(假设今天是2024-01-15,周一)本周开始 = pd.Timestamp('2024-01-15')本周结束 = 本周开始 + pd.Timedelta(days=6)df_本周 = df[(df['打卡日期'] >= 本周开始) & (df['打卡日期'] <= 本周结束)]
3.5 第五步:按时间分组统计
# 按月统计打卡次数月统计 = df.groupby(df['打卡日期'].dt.to_period('M'))['姓名'].count()# 按季度统计平均工龄季度统计 = df.groupby(df['打卡日期'].dt.quarter)['工龄(天)'].mean()
- .dt.to_period('M'):将日期转换为月份周期(如2023-05),方便分组。
四、自己动手试试!
4.1 第一步:创建测试数据
import pandas as pd# 模拟员工信息(包含生日、入职日期)员工表 = pd.DataFrame({'姓名': ['张三', '李四', '王五', '赵六', '钱七'],'生日': ['1990-05-12', '1985-08-23', '1992-11-03', '1988-02-18', '1995-07-30'],'入职日期': ['2018-03-15', '2020-07-01', '2019-11-20', '2021-12-10', '2022-06-01']})print("📋 原始数据(日期是字符串):")print(员工表)
4.2 第二步:转换日期并提取信息
# 统一转换员工表['生日'] = pd.to_datetime(员工表['生日'])员工表['入职日期'] = pd.to_datetime(员工表['入职日期'])# 提取信息员工表['出生年份'] = 员工表['生日'].dt.year员工表['出生月份'] = 员工表['生日'].dt.month员工表['星座'] = 员工表['生日'].dt.month.map({1:'摩羯',2:'水瓶',3:'双鱼',4:'白羊',5:'金牛',6:'双子', 7:'巨蟹',8:'狮子',9:'处女',10:'天秤',11:'天蝎',12:'射手'})员工表['入职年份'] = 员工表['入职日期'].dt.year员工表['工龄(年)'] = ((pd.Timestamp.now() - 员工表['入职日期']).dt.days / 365.25).round(1)print("\n🎯 处理后数据:")print(员工表[['姓名', '生日', '星座', '入职年份', '工龄(年)']])
4.3 第三步:筛选本周过生日的员工
# 获取今天的月和日今天 = pd.Timestamp.now()本月 = 今天.month今日 = 今天.day# 筛选生日在本月的员工本月生日 = 员工表[员工表['生日'].dt.month == 本月]# 筛选生日在本周的(略复杂,需要计算日期范围,这里简化)print(f"\n🎂 本月过生日的员工:{本月生日['姓名'].tolist()}")
五、办公实战1:考勤月度统计表
import pandas as pdimport numpy as np# 模拟全年考勤记录(随机生成)np.random.seed(42)日期范围 = pd.date_range('2023-01-01', '2023-12-31', freq='D')姓名列表 = ['张三', '李四', '王五', '赵六', '钱七']# 随机生成打卡记录(每人每天一条)考勤数据 = []for 姓名 in 姓名列表:for 日期 in 日期范围: 状态 = np.random.choice(['正常', '迟到', '早退', '请假'], p=[0.85, 0.05, 0.05, 0.05]) 考勤数据.append([姓名, 日期, 状态])df_考勤 = pd.DataFrame(考勤数据, columns=['姓名', '日期', '状态'])print("📋 考勤数据示例(前10行):")print(df_考勤.head(10))# 提取月份df_考勤['月份'] = df_考勤['日期'].dt.monthdf_考勤['月份名称'] = df_考勤['日期'].dt.month_name(locale='zh_CN')# 月度统计:每人每月迟到次数迟到统计 = df_考勤[df_考勤['状态'] == '迟到'].groupby(['姓名', '月份']).size().unstack(fill_value=0)print("\n📊 月度迟到统计表:")print(迟到统计)# 保存到Excel迟到统计.to_excel('月度迟到统计.xlsx')print("✅ 已保存为:月度迟到统计.xlsx")
六、办公实战2:自动计算工龄和退休年份
import pandas as pd# 员工信息(入职日期、出生日期)员工信息 = pd.DataFrame({'姓名': ['张三', '李四', '王五', '赵六'],'性别': ['男', '女', '男', '女'],'出生日期': ['1975-03-15', '1980-08-22', '1985-11-02', '1990-05-18'],'入职日期': ['2000-06-01', '2005-09-10', '2010-03-20', '2015-12-01']})# 转换日期员工信息['出生日期'] = pd.to_datetime(员工信息['出生日期'])员工信息['入职日期'] = pd.to_datetime(员工信息['入职日期'])# 计算年龄(截至今天)今天 = pd.Timestamp.now()员工信息['年龄'] = ((今天 - 员工信息['出生日期']).dt.days / 365.25).round(1)# 计算工龄(年)员工信息['工龄'] = ((今天 - 员工信息['入职日期']).dt.days / 365.25).round(1)# 计算退休年份(男60,女55)员工信息['退休年份'] = 员工信息.apply( lambda row: row['出生日期'].year + (60 if row['性别'] == '男'else 55), axis=1)# 计算剩余工作年数员工信息['剩余工作年数'] = (员工信息['退休年份'] - 今天.year).round(1)print("\n🎯 员工工龄退休分析:")print(员工信息[['姓名', '年龄', '工龄', '退休年份', '剩余工作年数']])# 筛选未来5年内退休的员工五年内退休 = 员工信息[员工信息['剩余工作年数'] <= 5]print(f"\n⚠️ 未来5年内退休的员工:{五年内退休['姓名'].tolist()}")
七、办公实战3:财务报表季度汇总
import pandas as pd# 模拟全年销售记录销售数据 = pd.DataFrame({'日期': pd.date_range('2023-01-01', '2023-12-31', freq='D'),'销售额': np.random.randint(1000, 5000, size=365),'成本': np.random.randint(500, 3000, size=365)})# 添加季度、月份列销售数据['季度'] = 销售数据['日期'].dt.quarter销售数据['月份'] = 销售数据['日期'].dt.month# 计算利润销售数据['利润'] = 销售数据['销售额'] - 销售数据['成本']# 按季度汇总季度汇总 = 销售数据.groupby('季度').agg({'销售额': 'sum','成本': 'sum','利润': 'sum','日期': 'count'# 交易天数}).rename(columns={'日期': '交易天数'})# 添加季度名称季度汇总.index = ['Q1', 'Q2', 'Q3', 'Q4']print("\n📊 季度销售汇总表:")print(季度汇总)# 计算环比增长率季度汇总['销售额环比'] = 季度汇总['销售额'].pct_change() * 100print("\n📈 季度销售额环比增长率:")print(季度汇总['销售额环比'].round(1))# 保存季度汇总.to_excel('季度销售报告.xlsx')print("✅ 已保存为:季度销售报告.xlsx")
八、常用日期时间操作速查表
| |
|---|
| pd.to_datetime(df['列']) |
| df['日期'].dt.year |
| df['日期'].dt.month |
| df['日期'].dt.day |
| df['日期'].dt.dayofweek |
| df['日期'].dt.day_name() |
| df['日期'].dt.quarter |
| df['日期'].dt.isocalendar().week |
| df['日期'] + pd.Timedelta(days=7) |
| (df['日期2'] - df['日期1']).dt.days |
| df[df['日期'].dt.month == 5] |
| df[df['日期'].dt.year == 2023] |
| df.groupby(df['日期'].dt.to_period('M')).sum() |
| df.groupby(df['日期'].dt.to_period('Q')).sum() |
九、重点总结:今天你学会了什么?
✅ 核心技能
- pd.to_datetime() - 统一日期格式
✅ 办公应用场景
✅ 效率对比
十、今日挑战:动手做!
任务1:生日提醒器
# 员工生日列表生日表 = pd.DataFrame({'姓名': ['张三', '李四', '王五', '赵六'],'生日': ['1990-05-12', '1985-08-23', '1992-11-03', '1988-02-18']})# 任务:提取月份和日,筛选出本月过生日的员工,并计算距离生日还有几天(忽略年份)
任务2:考勤异常统计
# 某月考勤数据(简化)考勤 = pd.DataFrame({'姓名': ['张三', '张三', '李四', '李四', '王五'],'日期': ['2024-01-05', '2024-01-06', '2024-01-05', '2024-01-06', '2024-01-05'],'状态': ['迟到', '正常', '正常', '早退', '旷工']})# 任务:将日期列转换为时间类型,按姓名统计每个人异常(迟到+早退+旷工)次数
任务3:合同到期提醒
# 合同信息合同表 = pd.DataFrame({'客户': ['A公司', 'B公司', 'C公司', 'D公司'],'签约日期': ['2022-03-15', '2022-07-01', '2023-01-10', '2023-05-20'],'合同期限月': [12, 6, 12, 3] # 月份数})# 任务:计算合同到期日,筛选出未来30天内到期的合同,并显示剩余天数
十一、明日预告
明天学自动化办公终极武器——批量处理与邮件发送!
- 如何用Python监控文件夹,新文件来了自动处理?
- 如何把多个Excel合并后自动美化并发送邮件给领导?
真正的自动化办公,从明天开始!
回复「Py-Day」获取今日挑战题解及完整代码。
评论区作业:分享你工作中遇到的日期处理难题,或者晒出你的代码截图!👇