日期与时间:DATEDIF、EOMONTH、工作日计算与年龄工龄

考勤表算工龄、合同算到期日、项目算工期——日期计算是行政财务的高频需求。Excel 的日期本质是序列值(1900 年 1 月 1 日为 1),所以加减即可得天数,但「整年整月」「工作日」「月末」这类业务口径要用专门的函数。这一篇按业务场景组织。

先记住:日期是数,时间是不足 1 的小数

  • 日期:=A2+1 加一天,=B2-A2 相差天数。
  • 时间:一天是 1,所以 12:00 是 0.5。=C2-B2 得到时间差,格式设为「小时:分钟」才能正常显示。
  • 时刻:NOW() 返回当前日期+时间;TODAY() 只返回日期,每天的报表用它都自动更新。

跨天的时间差(如 22:00 到次日 06:00)直接减会得负数,用 =MOD(C2-B2,1) 取模修正,这是打卡表常见处理——夜班跨零点的问题靠这一招解决。

DATEDIF:工龄与年龄的主力

语法:

=DATEDIF(start_date, end_date, unit)
unit 写法 返回
Y 完整年数
M 完整月数
D 天数
MD 忽略月年的天数差(官方不推荐使用)
YM 忽略年月的月数差
YD 忽略年的天数差

unit 必须是文本,公式里要带英文引号(见下面代码块),表格中省略引号以便阅读。

算实岁(周岁),start 填出生日期,end 填 TODAY():

=DATEDIF(B2,TODAY(),"Y")

要显示「5年3个月」,把三种单位拼起来:

=DATEDIF(B2,TODAY(),"Y")&"年"&DATEDIF(B2,TODAY(),"YM")&"个月"

注意事项(依据 Microsoft 官方文档):DATEDIF 是为兼容旧版 Lotus 1-2-3 保留的隐藏函数,输入时没有函数提示,直接手打即可;官方提示它在某些场景可能算错;MD 参数有已知缺陷,不建议使用;start_date 晚于 end_date 时返回 #NUM!。

工龄计算同理,把 B2 换成入职日期。有些公司按「虚年」口径(自然年差),那用 =YEAR(TODAY())-YEAR(B2) 更直接,口径以 HR 制度为准——同一张工资表里混用两种口径是常见纠纷来源,先把口径定死再写公式。

EOMONTH:月末与账期神器

语法:=EOMONTH(start_date, months),返回 start_date 之前或之后指定月数的月份最后一天。months 为正向后、为负向前、0 为本月;非整数会被截断。

=EOMONTH(TODAY(),0)      ' 本月最后一天
=EOMONTH(TODAY(),-1)+1   ' 本月第一天(上月最后一天加 1)
=EOMONTH(B2,1)           ' B2 次月最后一天(合同到期、账期)
=DAY(EOMONTH(B2,0))      ' 本月天数,闰年二月自动识别

本月第一天和最后一天这对组合是月报模板的常客:条件统计里用它做日期区间端点,报表打开就是当月数据,一个月改一次参数的麻烦永久消失。

版本说明:EOMONTH 从 Excel 2007 起内置,2003 及更早版本需要加载「分析工具库」加载项。结果是序列值,显示成五位数字就把单元格格式设为日期。

工作日计算:NETWORKDAYS 与 NETWORKDAYS.INTL

算「两个日期之间有几个工作日、去掉法定节假日」,用 NETWORKDAYS 系列。国际版语法:

=NETWORKDAYS.INTL(start_date, end_date, [weekend], [holidays])
参数 说明
start_date 开始日期,可早于或晚于 end_date
end_date 结束日期
[weekend] 可选,周末模式。数字 1 或省略=周六周日;11=仅周日;字符串用 7 个 0/1 表示(周一开始,1=非工作日),如 0000011 即周六日双休
[holidays] 可选,节假日日期区域,从工作日中排除

项目工期示例(单休:只有周日休):

=NETWORKDAYS.INTL(A2,B2,11,节假日!$A$2:$A$20)

weekend 参数填 11 表示「仅星期日」为非工作日,holidays 引用维护好的节假日清单,清单每年更新一次即可。版本方面,NETWORKDAYS.INTL 自 Excel 2010 起提供,更早版本只有单休/双休固定的 NETWORKDAYS。

反过来,「从今天起 30 个工作日后是哪天」用 WORKDAY.INTL:

=WORKDAY.INTL(TODAY(),30,1,节假日!$A$2:$A$20)

项目排期倒推交付日时必用,第五章的排期案例还会用到它。

实战:考勤月统计

假设考勤表有「应出勤」「实出勤」「迟到次数」三列原始数据,月度报表需要「满勤奖」判定:

=IF(AND(迟到次数=0,早退次数=0,请假天数=0),"满勤","")

再复杂点,统计当月迟到员工数:

=COUNTIFS(姓名列,"<>",迟到列,">0")

应出勤天数(工作日数)本身也用 NETWORKDAYS.INTL 算:开始日和结束日分别取参数表的月首月末,holidays 引用节假日清单。一张考勤月报里,日期函数出现在至少四个地方:标题、应出勤天数、月首月末条件、合同到期提醒。

日期相关的函数不复杂,复杂的是口径。动手前先和需求方确认三件事:按自然月还是考勤月、满勤是否含法定假、工龄按入职日期还是转正月。口径错了,公式再对也白搭。

节假日清单的维护

holidays 参数的效果完全取决于清单质量。维护建议:

  • 单独建「参数」工作表,A 列放当年法定假日期,一行一个。
  • 清单顶部写更新日期和维护人,过期一眼可见。
  • 每年 12 月先把次年假期填好,新年第一张报表就不会踩空。

清单是全表口径的源头,值得花十分钟维护,而且是参数化思维的又一次落地。

时间格式的小机关

  • Ctrl+; 输入今天日期,Ctrl+Shift+; 输入当前时间,适合做台账登记。
  • 时间求和超过 24 小时会被截断,格式用 [h]:mm 方括号写法才能累计——加班统计表的必备设置。
  • 跨午夜时段差用 MOD 修正(见开头)。
  • 时段判断(是否晚班)可以直接比较时段:
=IF(B2>TIME(20,0,0),"晚班","白班")

工龄口径对照表

同一份员工表里,不同口径算出的工龄能差出一年。下表把常见三种写法放在一起对比,选之前先问清楚 HR 或财务要哪种:

口径 公式 特点
实岁(精确到日) DATEDIF 加 Y 未过生日不算一年,最严谨
虚年(自然年差) YEAR(TODAY())-YEAR(入职) 跨年即+1,简单但偏大
按月折算 DATEDIF 加 M 再除以 12 用于按工龄发补贴的阶梯计算

第三种常用于工龄工资:每月额度乘以完整月数,比按年跳档更平滑,员工也不会有「差一个月就少一年钱」的抱怨。无论选哪种,在表头备注里写明口径,比事后解释省事得多。

新手常见误区

  1. 日期其实是文本。从系统导出的「2026.9.1」是文本,先 DATEVALUE 或「数据→分列」转换再计算,参考格式陷阱一篇。
  2. DATEDIF 拼字符串忘了再算一次。& 连接后变文本,「5年3个月」不能再参与比较。
  3. 节假日清单不更新。INTL 系列函数的效果完全取决于 holidays 区域,清单过期等于没设。
  4. 满 30 天算一个月还是按自然月算。没和需求方确认就开写,返工没商量。
  5. TODAY() 每天都变。简历上的「截至日期」、归档的历史快照不能用 TODAY(),否则每次打开数据都不一样;历史数据写死成具体日期最稳妥。

日期函数值得专门做一份「公司口径备忘」存进你的知识库——把 程序员简历与谈薪指南 里那种「把经验整理成可展示资产」的思路借过来,你的模板规范同样是可以拿出手的能力证明。

本章由 WorkBuddy 原创整理,函数行为以 Microsoft Excel 官方文档为准。