日期基础:TODAY、NOW、DATE 和年月日提取

先弄明白日期在 Excel 里是什么

Excel日期的本质是序列号

日期是 Excel 里最容易让人产生错觉的一类数据。单元格里明明显示着 2023/12/1,你把它和另一个日期相减却能得到天数,把它当文本拼接又会冒出一串五位数。要理解这一切,只需要记住一件事:Excel 内部的日期是一个序列号,显示的格式只是给它套了一件外衣。

这个序列号的规则很简单:在 Windows 版 Excel 默认的日期系统里,数字一代表 1900-1-1,数字二代表 1900-1-2,依此类推。所以 2023-12-01 对应的序列号是 45261,意思是从 1900-1-1 起算的第四万五千二百六十一天。把单元格格式改成常规,你就能看到这个真面目。

知道了这一点,很多现象就解释得通了。两个日期相减得到天数,本质上就是两个序列号相减;日期加七得到一周后的日期,本质上就是序列号加七;日期被当成文本拼接时出现五位数,本质上是拼接函数拿到了序列号而不是格式化后的字符串。

时间则是序列号的小数部分。零点五是中午十二点,零点二五是早上六点。所以一个带时间的单元格,其真实值可能是 45261.5,整数部分是日期,小数部分是时刻。这也是为什么有时候两个看起来一样的日期做比较会不相等:一个带了时间小数,一个只有整数部分,它们确实不是同一个数。

概念 真实值 显示值 常见误解
日期 45261 2023/12/1 以为存的是文本
日期时间 45261.5 2023/12/1 12:00 以为两个同日单元格必然相等
时间 0.5 12:00:00 以为时间是独立类型
文本日期 一串字符 2023/12/1 以为能直接参与日期运算
空单元格 0 1900/1/0 拿空单元格当日期会得到负数天数

表格最后一行值得特别注意。空单元格在参与日期运算时会被当成零,而零在日期系统里对应一个并不存在的日期,于是你会发现相差天数变成了负数或者大得离谱的数字。在做日期差计算之前,先用 ISBLANK 或 IF 判断一下是否为空,能避开相当多的诡异结果。

判断一个单元格到底是不是真日期,有个很朴素的办法:把格式改成常规,看它是否变成一个数字。变了就是真日期,没变就是文本。文本日期是数据清洗里最常见的坑之一,处理办法我们会在后面讲到。

TODAY 与 NOW:会自己走的时间

TODAY与NOW怎么选

TODAY 的语法极简,连参数都没有,直接写 =TODAY(),返回当前系统日期,只含日期不含时间,相当于序列号是一个整数。每次打开工作簿、每次触发重算,它都会自动更新到当天,这既是它的价值所在,也是它最容易惹麻烦的地方。

NOW 同样没有参数,写 =NOW(),返回当前的日期加时间,序列号带有小数部分。它的更新时机和 TODAY 一样,属于易失函数,任何一次重算都会刷新。两者合起来覆盖了绝大多数“自动记录当前时间”的需求。

它们最经典的用途是做动态计算,比如算账龄、算距离今天还有几天、算是否逾期。判断某笔应收款是否已经逾期,可以写 =IF(A2<TODAY(),"已逾期","未到期"),这里的 A2 是应收款到期日。注意小于号必须写在公式里,Excel 会把它当成比较运算符;公式前后要用反引号包起来只是本书的排版约定,真正在单元格里输入时并不需要。

再进一步,算距离到期还有几天,可以写 =A2-TODAY(),正数表示还有几天,负数表示已经逾期几天。正数时显示剩余天数、负数时显示逾期天数,一行公式就能覆盖两种情形,比写两层判断更简洁。如果还要区分今天到期的情况,写成 =IF(A2<TODAY(),"已逾期",IF(A2=TODAY(),"今天到期","未到期")),三层判断依次覆盖逾期、当天、未到期三种状态。

再比如做一个自动高亮的到期提醒,可以用条件格式,规则公式写 =A2-TODAY()<=3,意思是距离到期不超过三天就标红。条件格式里的公式同样要写成能被求值为真假的表达式,配合 TODAY 就能实现完全自动的提醒效果,不用每天手工改。

需要提醒的是,易失函数会让工作簿在每次操作时都触发重算。如果一个几千行的大表里塞了几百个 TODAY(),打开和编辑时会有明显卡顿。更好的做法是在一个固定单元格里写一次 =TODAY(),比如放在参数区的 H1,其他地方统一引用 $H$1。这样既保持了集中控制,也减少了重算负担。

如果你想要的是静态时间戳,也就是记录下“填表那一刻”并且不再变化,那就不该用函数,而应该用快捷键。输入当天日期按 Ctrl 和分号,输入当前时间按 Ctrl + Shift 和分号,两者一起按就先输日期再输时间。这样写入的是固定值,不会因为明天打开文件而改变。

DATE 与 DATEVALUE:造出一个真正的日期

DATE 的作用是把年、月、日三个数字组装成一个真正的日期序列号,语法是 =DATE(年, 月, 日)。它最重要的特性是会自动进位,这一点非常实用。

月份超过十二会自动进位到下一年:

=DATE(2023,14,1)

结果是 2024-2-1,因为第十四月等于下一年的第二月。同理,月份写零或负数会往前退:=DATE(2023,0,1) 得到 2022-12-1。

日期超过当月天数同样自动进位:=DATE(2023,2,30) 得到 2023-3-2,因为二月只有二十八天,多出来的两天进了三月。这个特性让它非常适合做按月的批量推算,不用自己去判断每个月有多少天:

=DATE(YEAR(A2),MONTH(A2)+3,DAY(A2))

这个公式把 A2 的日期往后推三个月,月份直接加三,剩下的交给 DATE 自己处理。不过要注意一个边界情况:如果原日期是某月三十一日,推到只有三十天的月份时会自动进到下一月的第一天,比如一月三十一日加一个月会得到三月三日而不是二月二十八日。如果业务上要求落在月末,就要用专门的月末函数,那部分内容在 日期推算:EDATE、EOMONTH、DATEDIF、NETWORKDAYS 里讲。

DATE 还常用来把散落的年、月、日三列合成一列日期:

=DATE(A2,B2,C2)

只要 A、B、C 三列分别是年、月、日的数字,一格公式就能生成真正的日期,可以直接参与后续计算,比拼接再转换可靠得多。

DATEVALUE 则是把文本形式的日期转成序列号,语法是 =DATEVALUE("2023-12-1")。它主要用来对付从系统导出的文本日期。需要提醒的是,DATEVALUE 的解析结果受系统区域设置影响,03/04/2023 在美式设置下是三月四日,在英式设置下是四月三日。如果数据来源复杂,更稳妥的做法是先用文本函数拆出年月日,再用 DATE 组装,虽然多写几个字,但结果完全可控。

年月日提取与星期

从日期里取组成部分,用的是 YEAR、MONTH、DAY 三个函数,语法都是单参数:=YEAR(A2) 返回四位数的年份,=MONTH(A2) 返回一到十二的月份,=DAY(A2) 返回一到三十一的日。这三个函数返回的都是数字,可以直接参与比较和运算。

它们最常见的用途是分组统计。比如按月份汇总销售额,可以先加一列 =MONTH(A2) 得到月份数字,再用 SUMIF 按月份求和;或者直接写 =SUMPRODUCT((MONTH(A2:A100)=3)*C2:C100) 一步到位。多条件统计的系统写法可以在 SUMIFS 多条件统计:日期区间加多字段 里看到完整讲解。

取星期用 WEEKDAY,语法是 =WEEKDAY(日期, [返回类型])。第二个参数决定一周从哪天开始、返回值怎么编号,最常用的是写二,表示星期一返回一、星期日返回七:

=WEEKDAY(A2,2)

写成这样之后,判断是否为周末就非常简单:=IF(WEEKDAY(A2,2)>5,"周末","工作日")。做考勤表、排班表、判断加班与否,几乎都靠这一句。

如果想直接显示成中文星期几,可以外套 TEXT:=TEXT(A2,"aaaa") 得到“星期一”,=TEXT(A2,"aaa") 得到“一”。注意这个格式代码在不同语言环境下行为不同,在英文系统里 aaaa 出来的是 Monday。如果报表要发给不同语言环境的同事,更稳妥的做法是用 WEEKDAY 拿到数字,再用 CHOOSE 映射成中文:

=CHOOSE(WEEKDAY(A2,2),"周一","周二","周三","周四","周五","周六","周日")

时间部分的提取用 HOUR、MINUTE、SECOND,分别返回时、分、秒,语法同样是单参数。它们常用来计算打卡时长,比如 =(HOUR(B2)*60+MINUTE(B2))-(HOUR(A2)*60+MINUTE(A2)) 得到两次打卡之间相差的分钟数。如果两次打卡跨了午夜,结果会是负数,此时要加上一千四百四十再取模,写成 =MOD(下班分钟数-上班分钟数,1440),取余运算会自动把负数修正成正的时长。

按季度分组也是高频需求,写法很简单:=ROUNDUP(MONTH(A2)/3,0) 得到一到四的季度编号,或者写 ="第"&ROUNDUP(MONTH(A2)/3,0)&"季度" 直接生成标签。季度编号是数字,可以直接用于排序和条件统计,比文本标签更灵活,需要展示时再拼上前缀也不迟。

按周分组可以先算该日期属于当年的第几周:=WEEKNUM(A2,2),第二个参数写二表示周一为一周的第一天。这个函数在做周报和按周汇总时非常实用,配合 YEAR 一起作为分组键,就能避免跨年时周次混淆的问题。

格式化显示与常见错误

日期显示成什么样,完全由单元格格式决定,与真实值无关。选中单元格按 Ctrl + 1,在数字选项卡里选日期或自定义,就能改变外观。常用的自定义格式代码有:yyyy-mm-dd 显示成带前导零的年月日,yyyy年m月d日 显示成中文格式,yyyy-mm-dd hh:mm 带时分。

这里有个容易混淆的点:格式代码里的 m 在紧跟 h 之后时会被解释为分钟,否则解释为月份。所以写 hh:mm 时分秒没问题,写 yyyy-mm-dd 要用小写 mm 表示月。如果确实需要在同一个格式里同时出现月和分,月份用 m,分钟前加一个 h 上下文即可区分。

最常见的错误是拿文本日期去计算。症状是:看起来是日期,做减法却报错,或者求和结果为零。判断办法是把格式改成常规,如果还是显示 2023/12/1 那就是文本。转成真日期有三条路:一是 DATEVALUE,二是用分列功能,在第三步里选择日期格式,三是用文本函数拆开再用 DATE 组装。

第二条路其实最省事,尤其适合整列都是文本日期的情况:选中整列,点数据选项卡的分列,一路下一步到第三步,在列数据格式里选日期,确定即可。分列能一次性把整列转成真日期,比写公式快,也不需要拖填充。

还有一个容易忽略的点是导出给其他系统时的格式。很多业务系统导入日期时只认 yyyy-mm-dd 这种带前导零的紧凑格式,而 Excel 默认显示的 2023/12/1 会被拒绝。稳妥做法是导出前先用 TEXT 生成一列纯文本日期:=TEXT(A2,"yyyy-mm-dd"),把这一列粘成数值后再另存,能避免绝大多数导入失败。注意这样生成的是文本,导入系统没问题,但别拿它回来做日期运算。

另一个常见错误是年份只写两位数。Excel 对两位年份有自己的解释规则:零到二十九被解释为二零零零到二零二九年,三十到九十九被解释为一九三零到一九九九年。所以输入 29/1/1 得到的是二零二九年,输入 30/1/1 得到的是一九三零年。录入数据时务必写全四位年份,别指望系统猜对你的意思。

关于兼容性,Windows 版 Excel 默认使用一九零零日期系统,而老版本的 Mac 版 Excel 默认使用一九零四日期系统,两者的序列号相差一千四百六十二天。如果把文件在两个平台之间来回传,日期可能整体偏移四年。现在的 Mac 版已经默认与 Windows 一致,但打开老文件时仍可能遇到,可以在选项里检查“使用 1904 日期系统”这一项是否被勾选。

常见问题

TODAY 和 NOW 的区别是什么

TODAY() 只返回当天日期,序列号是整数,显示出来是 2023/12/1 这样的形式;NOW() 返回当前的日期加时间,序列号带小数,显示出来是 2023/12/1 14:30 这样的形式。两者的共同点是都没有参数、都属于易失函数,每次重算都会刷新。

实际选择时看你需要什么粒度:只关心是哪一天就用 TODAY,需要精确到几点几分就用 NOW。如果你用 NOW 却只想要日期部分,可以外套 INT 取整,写成 =INT(NOW()),或者更直接地改用 TODAY()。

怎么让日期不再自动变化

用函数做不到,因为 TODAY 和 NOW 的设计就是每次重算都刷新。想要固定的时间戳,必须用快捷键输入静态值:按 Ctrl 和分号写入当天日期,按 Ctrl + Shift 和分号写入当前时间。这样写入的是普通数据,不会变化。

如果已经用了公式而现在想固化,可以选中单元格复制,再用选择性粘贴选数值粘回去,公式就变成了当时的那个值。不过要注意,选择性粘贴之后日期可能显示为序列号,需要重新把格式设成日期。

为什么两个看起来一样的日期不相等

因为其中一个带了时间部分。单元格格式可能只显示了日期,但真实值是 45261.5,而另一个是 45261,两者做等号比较必然返回假。解决办法有两个:一是比较时用 INT 把两边都取整,写成 =INT(A2)=INT(B2);二是比较日期区间,写成 =AND(A2>=开始日,A2<结束日加一天)。

第二种写法更推荐,因为它不依赖时间部分是否为零,判断逻辑也更清晰:大于等于开始日,且小于结束日的次日,就能覆盖结束日当天的全部时刻。

怎么用 DATE 计算三个月后的日期

直接把月份加三即可,进位交给 DATE 自己处理:

=DATE(YEAR(A2),MONTH(A2)+3,DAY(A2))

需要注意月末的边界情况。如果原日期是一月三十一日,加一个月会得到三月三日,因为二月没有三十一日。如果业务规则要求落在月末而不是顺延,应该用专门的月末推算函数,参见 日期推算:EDATE、EOMONTH、DATEDIF、NETWORKDAYS。那里也讲了如何计算两个日期之间相差的整月数和整年数。

系统导出的日期是文本,怎么批量转成真日期

三种办法。最快的是分列:选中整列,数据选项卡点分列,下一步到第三步,列数据格式选日期,确定即可一次性转完,不需要写任何公式。第二种是 DATEVALUE,适合格式规整的文本。第三种是用文本函数拆出年月日再用 DATE 组装,适合格式混乱、区域设置有歧义的情况。

转完之后一定要验证。加一列 =ISNUMBER(A2),全部返回真才算转成功,返回假的行说明还有残留问题,需要单独处理。这个验证步骤能帮你及时发现转换失败的行,而不是等到统计结果出错再回头排查。