我最早被这个需求打动,是给一位做HR的朋友做“员工生日与合同到期一体化提醒表”的时候。她用Excel管理几百号人的档案,抱怨最多的一句话是:今天过的到底是谁的生日、谁的合同快到期了,打开表格第一眼根本看不出来。后来我在表格里引入NOW和TODAY这两个时间函数,把年龄计算、下一次生日倒计时、合同剩余天数全部做成了自动刷新。表格一改完,她再也不用每天手动改日期,开会前打开文件扫一眼,哪些人要续约、哪些人马上过生日,几乎零成本掌握。
这篇文章就把这套“时间魔法”完整拆开:从Excel日期的最底层逻辑讲起,再到NOW与TODAY的区别、动态年龄的各种算法、生日和合同到期的动态倒计时,最后给一个可以直接套用的人事信息表案例。无论你是做行政、人事、项目管理,还是只想给家人做一张“孩子成长天数表”,这里的公式都能直接复制改着用。
1. 动态日期的“地基”:NOW和TODAY到底在算什么
我先讲一个很多人忽略的事实:Excel里日期不是一个“字”,而是一个“数字”。只有理解这一点,你才能真正明白为什么NOW和TODAY能帮你做动态年龄和倒计时。
1.1 Excel的日期本质上是一串序列数
在Windows版Excel里,系统会把1900年1月1日当作序列数1,1900年1月2日就是2,依此类推。今天我们打开Excel,如果在一个单元格里输入一个日期,把一个比较新的日期用“常规”格式显示,你会看到一串四五万的大数字,比如2024年11月1日的实际值大约是45000多。日期之所以能在屏幕上显示成“2024/11/1”,只是因为你给这个单元格套了日期格式,真正参与计算的底层值始终是一个数字。
这个底层逻辑的意义在于:两个日期相减,结果直接就是相差的天数。比如“截止日期单元格减去今天日期单元格”,得到的就是剩下的天数。年龄、倒计时、工作年限,本质上都是在“数字相减”的基础上做文章。真正要把“数字”变回“有意义的时间文本”,需要借助NOW、TODAY、DATEDIF之类的函数,把时间维度翻译成人能看懂的年月日。
1.2 NOW和TODAY:一个带“秒针”,一个只翻日历牌
这两个函数都是直接读电脑系统当前时间,区别在于:
TODAY():只返回当前日期,底层是一个整数,没有时间小数部分。NOW():返回当前日期加当前时间,底层是整数加小数,比如某个时刻的真实值是45266.7583,前面的整数代表日期,后面的小数代表时间。
如果只把单元格设置成日期格式,两者看起来相同;但把格式切成“yyyy-mm-dd hh:mm:ss”,NOW()会实时显示出几点几分几秒,TODAY()永远只显示当天00:00。顺便提醒一句:NOW()里哪怕只是打开了文件没做任何操作,重新计算后它也会跳到当前时刻;TODAY()相对“温和”,它只关心是哪一天,不关心是白天还是晚上。
什么时候用NOW,什么时候用TODAY,我的习惯很简单:只关心“还剩几天”就用TODAY;需要记录操作到“几分几秒”、或做某些时间精度要求高的提醒,才用NOW。因为NOW的刷新会让表格内容在高频重算时发生肉眼可见的变化,不如TODAY稳定。
1.3 易失函数与“每次打开都变”的机制
NOW和TODAY在Excel里都被归为“易失函数”(volatile functions),意思是每当工作表重新计算一次,函数就得重新读当前系统时间。默认情况下,Excel在你修改任何一个单元格、打开工作簿、或按F9强制计算时,都会触发全表重算,因此这些函数会跟着跳到当前时间。这就是为什么很多用户第一次做动态表特别不适应:昨天填好的“今天”到今天打开,怎么自己变了?明明只有我是唯一使用者,表格自己“长了腿”。
如果你需要保留某一天的固定日期作为历史快照,不要用TODAY,而是按快捷键Ctrl + ;,这是插入“静态当前日期”的常用方式;要插入固定当前时间用Ctrl + Shift + ;。这条经验在自动化人事表单里特别重要,因为你不希望一条“登记日期”刚录完,第二天自己悄悄变成第二天,让流程记录失真。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 动态年龄计算:从“周岁”到“年月日”全自动
标题里写了“动态年龄计算”,这个词在人事、教育、会员管理场景里太常见了。传统的错误做法是手动填年龄,第二年发通知时发现全员年龄都过期了。用TODAY函数做年龄,只要出生日期正确,年龄每天都会自动推进,完全不需要人工干预。
2.1 最省心的王牌函数:DATEDIF
Excel里有个不太被官方帮助文档主动介绍的日期函数叫DATEDIF,中文名通常叫“DATEDIF”,输入时一般不会出现在自动提示列表中,甚至有些用户以为它是加载项。实际上从很久以前它就能用,专门计算两个日期之间的差值,而且可以按“年”“月”“日”分别输出,非常贴合年龄计算:
excel复制=DATEDIF(出生日期, 结束日期, 单位)
第三个参数单位有几种:"Y"返回满的年数,"YM"返回忽略年和日之后的月数,"MD"返回忽略年和月之后的天数。举例来说,如果一个人的出生日期在B2单元格,到今天动态年龄的计算公式可以拆成三部分:
excel复制=DATEDIF(B2,TODAY(),"Y")
=DATEDIF(B2,TODAY(),"YM")
=DATEDIF(B2,TODAY(),"MD")
第一个公式得到完整周岁,第二个得到刨去整年后剩余的月数,第三个得到刨去整年和整月后剩余的天数。这样拆出来,即使出生日期和今天是同一天,也会返回0,不会误报成一岁。因此DATEDIF其实是EXCEL动态年龄方案里最值得依赖的基础函数,同时兼容几乎所有主流版本,实用价值非常高。
2.2 拼出“XX岁XX个月XX天”的可读结果
单独的周岁数往往不够直观,尤其是做育儿记录或老人关怀项目,人们希望看到“孩子已经3岁2个月15天”。你可以把三个DATEDIF结果拼接起来:
excel复制=IF(B2="","",
DATEDIF(B2,TODAY(),"Y")&"岁"&
DATEDIF(B2,TODAY(),"YM")&"个月"&
DATEDIF(B2,TODAY(),"MD")&"天")
我在公式外层套了一个IF判断,出生日期为空时返回空字符串。这个细节很实用,因为如果你直接引用空单元格,DATEDIF会把空单元格当成1900年1月0日之类的极端日期,算出几百岁,非常尴尬。实际使用时,还可以再优化一下,当“天”为0时省略,比如“3岁2个月”,只要用IF包装一下即可。
2.3 不用DATEDIF也能算年龄的原理
有人会问:为什么不用DATEDIF也有人能算出年龄?常见的替代公式是:
excel复制=YEAR(TODAY())-YEAR(B2)-IF(DATE(YEAR(TODAY()),MONTH(B2),DAY(B2))>TODAY(),1,0)
这个公式的逻辑是这样的:先用年度直接相减,例如出生于1995年,今年是2024年,先得出29这个“毛年龄”。但这只考虑年份,不考虑生日过没过。例如今天是2024年3月10日,如果生日是2024年5月1日,直接按年份算出来29就不对,因为到5月1日才满29周岁。所以这里用IF判断“今年生日那一天是否大于今天”,如果今年生日还没到,就在毛年龄上减掉1,结果是准确的周岁。
这段解释也是Excel电子表单从业者互相交流时常讲必讲的内容。手动写公式的优点是兼容那些DATEDIF特殊字符出问题的旧文件,缺点是需要把逻辑编对,对新手容易写错。我的建议是:初学直接用DATEDIF,想深入理解年龄本质,再把YEAR方案的推导过程手工走一遍。
2.4 动态“剩余多少天成年”或“多少天退休”
除了静态年龄,动态年龄计算的延伸常常是判断“距离某个里程碑还有多少天”。例如会员系统中,想算一个孩子离18岁生日还有几天,可以先把成年日期算出来,再减去今天:
excel复制=DATE(YEAR(B2)+18,MONTH(B2),DAY(B2))-TODAY()
这个公式把出生日期中的年份加上18,日、月保持不变,形成18周岁当天的日期,再减去当前日期。结果为正数表示还没成年,结果为0表示今天成年,结果为负数表示已经成年。要把“是否成年”变成清晰的文字判断,可以再包一层:
excel复制=IF(B2-TODAY()>=0,"未满18岁,差"&B2-TODAY()&"天","已满18岁")
类似方法也可以算退休倒计时、合同转正提醒等。凡是“以某个出生日期为基准,加上固定年数得到一个关键节点”的场景,都可以用这类DATE基准运算。
3. 动态倒计时与自动提醒:让表格“算着日子”跑起来
倒计时和年龄计算思路类似,但倒计时更关注“目标日期─今天”这条减法。若想做一个长期用的提醒工具,通常还要处理“下一个生日是哪一年”的动态判断,单纯减今天并不够。
3.1 最基础的剩余天数公式
假设目标日期在C2,想显示“距离目标日还有多少天”,直接在另一格写:
excel复制=C2-TODAY()
C2必须是一个标准日期,公式结果默认是日期格式,会显示得很难看,因为Excel可能会把数字天数显示成某个日期。所以输入公式后,记得把单元格格式设置为“常规”或“数值”。如果你希望目标日期已经过去了就显示0而不是负数,可以用MAX把负值托底:
excel复制=MAX(0,C2-TODAY())
这条公式在做“已经过期不算剩余、只统计有效剩余”的场景下很好用。但要提醒一句:它是把过期天数也强行清零,如果你还想看到逾期几天,就不要用MAX,保留负数并借助条件格式把负数标红更有意义。
3.2 让“生日倒计时”自己找到下一次生日
很多新手以为在D2写“生日日期−TODAY”就是生日倒计时,其实这是错的。因为某人的生日如果是1990年2月11日,那么“1990年2月11日”减去今天可能是一个几百天的负数,因为那个日期早已过去。我们要算的不是“出生那天距离今天有多少天”,而是“今年或明年的生日距离今天还有多少天”。
正确的动态生日倒计时思路是:先去构造“今年的生日”,如果今年的生日还没到,它就是目标日;如果已经过去了,就改成“明年的生日”,再减去今天。公式如下:
excel复制=IF(
TODAY()>DATE(YEAR(TODAY()),MONTH(B2),DAY(B2)),
DATE(YEAR(TODAY())+1,MONTH(B2),DAY(B2)),
DATE(YEAR(TODAY()),MONTH(B2),DAY(B2))
)-TODAY()
我来解释一下它为什么准确:DATE(YEAR(TODAY()), MONTH(B2), DAY(B2)) 生成的是“今年某人的生日日期”,比如今天2024年11月20日,某人生日是1990年2月11日,那么生日日期就是2024年2月11日。由于这个日期已经小于今天的日期,外层的IF判断为真,于是改为生成“2025年2月11日”,最后减去今天,得到从当前日期到下一个生日的准确数量。如果是自己生日在今天,DATE生成今天,外层IF为假,结果刚好是0,提醒会很准确。
3.3 把多个事件放到一张“倒计时面板”
单算一个生日意义有限,实际工作中更多是把许多事项汇总起来,做成一张“到今天还剩几天”的监控面板。推荐结构如下:
| 事项 | 目标日期 | 距离天数 |
|---|---|---|
| 项目验收 | 2025-01-15 | =B2-TODAY() |
| 客户续费 | 2025-02-01 | =B3-TODAY() |
| 设备年检 | 2025-03-20 | =B4-TODAY() |
这里有个建议:不要为了“好看”把日期那一列用文本输入“2025年1月15日”,因为文本无法参与减法计算。应当输入真正的日期,需要时再用自定义数字格式变成“yyyy年m月d日”。凡是日期参与运算的表,尽量保持“底层是日期、表层是格式”的规范,否则后期公式全都会出错。
3.4 条件格式自动高亮“30天内到期”
有了距离天数后,靠肉眼扫描几十行数字并不高效。我们可以给“距离天数”这一列做条件格式,让30天内的数据自动变黄,已经过期自动变红。
操作步骤:选中从F2到F100的区域,点击【开始】→【条件格式】→【新建规则】→【使用公式确定要设置格式的单元格】,输入:
excel复制=AND(F2>=0,F2<=30)
F2是第一行数据的单元格,注意去掉行号前的美元符号,或根据实际区域调整锁定方式。填充选择浅黄色,意思是“剩余天数在0到30天之间,即将到期”。再新建一条规则:
excel复制=AND(F2<0, F2<>"")
填充为浅红色,表示“已经过期”。设置完成后,30天内的事项一眼就能看到,不必每天人工对比日历。
如果不显示标红而显示成一串“####”,一般不是公式错,而是列宽太窄或日期负数导致显示异常。处理方法在后文常见问题里细说。
3.5 工作日倒计时更有“职场味”
许多项目类倒计时不关心周六日,只关心“距离截止日期还剩几个工作日”,这时候用NETWORKDAYS比直接相减更贴近实际:
excel复制=NETWORKDAYS(TODAY(),C2)
如果需要排除法定节假日,可以在工作表里维护一段“节假日区域”,然后把区域引用作为第三个参数:
excel复制=NETWORKDAYS(TODAY(),C2,$G$2:$G$20)
NETWORKDAYS的算法是:计算开始日期和结束日期之间的工作日数,周末自动跳过。要注意这个函数默认把周六周日当休息日,如果你的公司是周天周一休息,可以使用NETWORKDAYS.INTL函数,并设置周末参数。第三个节假日区域是可选的,它可以引用一个手工维护的“放假日期清单”,实测比人工计算强得多。
4. 一个可以直接抄作业的人事信息表案例
前几章偏原理,这一章我们来搭一个名副其实的“动态年龄与到期提醒”信息表。我会把需求说具体:假设人事专员要管理员工姓名、出生日期、入职日期、合同到期日。表格打开后要自动显示每个员工的年龄、司龄、合同剩余天数,并把状态分成“正常、即将到期、已到期”三档,同时用颜色提醒。
4.1 字段设计与首行公式
我建议把工作表的第一行作为说明,第二行开始放正式数据。以B列为姓名、C列为出生日期、D列为入职日期、E列为合同到期日,其他列依次放年龄、司龄、剩余天数、状态。
年龄列F2可以这么写,输出文字版年龄:
excel复制=IF(C2="","",DATEDIF(C2,TODAY(),"Y")&"岁"&DATEDIF(C2,TODAY(),"YM")&"个月")
司龄列G2:
excel复制=IF(D2="","",DATEDIF(D2,TODAY(),"Y")&"年"&DATEDIF(D2,TODAY(),"YM")&"个月")
合同剩余天数H2:
excel复制=IF(E2="","",E2-TODAY())
状态列I2:
excel复制=IF(E2="","",IF(E2-TODAY()<0,"已到期",IF(E2-TODAY()<=30,"即将到期","正常")))
这个状态公式会自动把所有已过期的合同标成“已到期”,把30天内的标成“即将到期”,30天以上则显示正常。如果有“当天就是到期日”,E2-TODAY等于0,会被第二个IF判断为“即将到期”,因为0小于30,这样不会漏掉当天到期的合同,比只判断负数更稳妥。
4.2 设置状态列的颜色提醒
选中I列状态数据区域,条件格式里添加两条规则,规则类型仍是“仅对包含以下内容的单元格设置格式”更方便:
- 单元格文本等于“已到期” → 红色填充
- 单元格文本等于“即将到期” → 黄色填充
如果希望“合同剩余天数”列也跟随变色,可以用公式规则并把应用到整个A到I区域。例如选中A2:I200,按行方向使用相对引用,给整行调用绿色还是蓝红:
excel复制=$I2="已到期"
这条公式中的$I2,列前有美元符号锁定I列,行前不加锁,可以跟随每一行的行号变化,所以当第2行状态为已到期时,第二整行会标红。使用条件格式的另一条方案是仅让H列数字变色,但我更推荐整行标识,因为整行更容易扫视。
4.3 批量加入新员工时公式自动延伸
大多数人事表会不断添加新员工,但手工拖动公式容易漏。将数据区域选中后按Ctrl + T转成“表格”,Excel会自动把每列公式扩展到新插入的行。这样新录入一条员工信息后,F到I列公式会自动填充,不需要再挨个拖动。转入表格后,如果每个列头旁出现筛选项,还可以用“状态”筛出即将到期的人,甚至配合切片器快速查看“已到期”这类提醒类别。建议把表格的总行数留足一些,比如从第2行到第1000行,以免后续加人加行时长期需要调整区域引用范围。
4.4 面板加一个“最后更新”时间戳
如果要告诉浏览者“这张表当前数据是何时刷新的”,可以找一个不起眼的单元格加入:
excel复制=NOW()
再给它自定义格式为“yyyy年m月d日 hh:mm”,保存为更新于yyyy年m月d日 hh:mm。但要注意:这个时间不会在表格闲时自动走秒,只有发生重算时才会刷新。刚才第一章节讲了易失函数会刷新,但有些人把Excel设成了“手动重算”,这时可以按F9强制刷新。如果你要让状态尽量准确,建议保持Excel默认的“自动重算”。
5. 你可能遇到的“时间坑”与排查技巧
这套方案我已用了很久,但这几个问题反复被同事和学员碰到。不算高深,却足以让表格在交付瞬间“看起来很失败”,所以值得单独写成一份避坑清单。
5.1 日期列显示成一串####,为什么不显示数字
单元格显示“####”最常见原因有三个:
- 列宽太窄,日期格式放不下,拉宽即可;
- 单元格里是负日期或负时间,Excel默认不显示;
- 格式错乱,把一个很大的序列数当成日期显示。
排查时先选中这个单元格,看编辑栏里的真实值是日期还是数字,然后把列宽拉大,再设置“日期”格式。如果真实值本身是负数,Excel无法显示日期,就换一种格式查看“数值”。
5.2 DATEDIF一直报#NUM!或结果不对
DATEDIF对两个日期先后敏感,开始日期比结束日期晚时,会直接报错。比如把公式写成了:
excel复制=DATEDIF(TODAY(),C2,"Y")
C2出生日期早于今天,那么TODAY比C2大,这样公式的开始日期在后面,不合理,因此会报错。正确方向永远是“较早的日期放前面、较晚的日期放后面”。若结果不对但没报错,建议检查一下C2单元格是不是“真正的日期”,还是“文本日期”。文本日期经常靠左对齐,参与计算时容易被当成文本不参与减法和DATEDIF,触发VALUE类型错误。可以用ISNUMBER(C2)来判断C2是不是数值,如果返回FALSE,说明它是文本。
5.3 打开别人发来的表,日期全部错位或变成另一套数
常见原因是两台电脑的系统日期格式不一样,或单元格保存的是“文本日期”。比如在中文系统里“2024/11/1”能正常识别,但在某些英文系统或老版本中可能被当成“2024年1月11日”之类。解决方法是:统一录入标准ISO日期“2024-11-01”,或确保单元格格式已设为“日期”而不是“文本”,文本日期是最容易造成跨平台错乱的罪魁祸首。另请注意,新版Excel使用1900日期系统,而极少数第三方软件生成的日期从1904年开始,会出现整体相差4年的现象。若收到外部导出的文件日期差四年,先查文件来源的日期系统设置。
5.4 手动重算模式下怎么都不更新
如果【公式】→【计算选项】里选了“手动”,打开工作簿并且修改单元格后,NOW和TODAY都不会自动刷新。此时按F9可以重算整个工作簿,按Shift + F9只重算当前工作表。建议把这份工作簿固定使用“自动重算”,除非文件太大、计算太卡,否则不要让动态时间函数保持迟钝。若为了性能必须设成手动,那就在页面顶部写一行提示:请按F9刷新动态日期。
5.5 用NOW()记录“登记时间”后发现时间总变
NOW()是易失函数,这就是它不能当静态“登记时间”的原因。比如填表时用NOW()标记“填报时间”,第二天打开一看,时间变成了打开时的当前时间,整个填报记录就会失真。正确做法是用快捷键Ctrl + Shift + ;录入静态时间,或写一段简单的VBA一次性写入固定日期时间。这一点和TODAY快照同理,最好在表格说明文档里明确标注哪些列是动态的、哪些是用快捷键固定的。
最后再分享一个我自己踩过坑后形成的习惯:做这类动态时间表格,一定在文件里单独留一个“说明页”或在表头醒目标注“本表涉及TODAY/NOW函数,打开时会自动更新日期”。原因很简单,当你把做好的自动提醒表发给同事,同事第二天打开说“这个日期怎么跟我昨天看到的不一样”,如果没有任何解释,他大概率会以为表坏了。加一句标注,不仅让人安心,也避免了后续反反复复的“表出错”质疑。今天文中用到的所有公式都能复制后直接落地,建议先从一张三五行的“生日倒计时练习表”入手,运行通了再套进复杂人事系统,这样效率最高。
