请假三天,从周一 23:00 到周四 01:00——这算几天?如果按精确时长算,只有 26 小时,也就是 1.08 天;如果按日历日期算,跨越了周一到周四共 3 个日期差。两个答案都能算出来,但只有一个是请假场景需要的。这就是「自然日数」和「总天数」这两个口径的分野。
两个口径的定义
总天数是精确时长的换算:把两个时间点之间的毫秒差除以一天的毫秒数。
总天数 = (结束时间戳 − 起始时间戳) ÷ 86400000
它是一个小数,反映的是「实际经过了多长时间」。
自然日数只比较日历日期,忽略具体时刻。
自然日数 = 结束日期 − 起始日期(按日期算)
今天到明天就是 1 天,不管具体是几点到几点。
一个具体对比
假设起始时间是今天 23:00,结束时间是明天 01:00。
按总天数算:2 小时 ÷ 24 小时 = 0.083 天。
按自然日数算:从今天到明天,1 天。
两个结果差了十几倍。这不是哪个算错了,而是两个口径回答的是不同的问题。总天数回答「实际过了多久」,自然日数回答「跨越了几个日期」。
各自的适用场景
用自然日的场景:请假天数、工期天数、账期、合同期限、活动持续天数、住院天数。这些场景的共同特点是「按天计」,与具体时刻无关。请一天假就是一天,不管你是早上八点开始还是晚上八点开始。
用总时长的场景:系统运行时长、任务执行耗时、两次事件之间的间隔、缓存有效期、Token 过期时间。这些场景关心的是「实际经过了多少时间」。
判断方法很简单:问自己「这个数字是按日历算的,还是按时长算的」。如果答案是「按日历」,用自然日。
「包含结束当天」的开关
很多工具提供一个「包含结束当天」的选项,勾选后自然日数会加 1。
这个选项的存在是因为「算不算首尾」有两种习惯。
从 1 号到 3 号,不包含结束当天是 2 天(1 号到 2 号算一天,2 号到 3 号算一天),包含结束当天是 3 天(1、2、3 号各算一天)。
哪种口径正确取决于场景。请假场景通常用「包含结束当天」——请 1 号到 3 号,就是请了 3 天假。而「间隔几天」这种表述通常用不包含——1 号和 3 号之间隔了 2 天。
所以看到天数结果时,要先确认工具用的是哪种口径。同一个区间,两种口径的结果可能差 1。
工作日是另一个维度
除了自然日和总天数,还有一个「工作日」口径。
工作日的定义是:日期区间内排除周六和周日的天数。它属于「自然日」的变体——同样只看日期,但在计数时跳过了周末。
工作日口径有两个已知的局限。一是不考虑法定节假日*,春节、国庆这些假期会被算成工作日。二是*不考虑调休,因调休而上班的周末会被排除在外。
所以工作日数只能作为粗略估算。如果用于工期安排、合同期限这类需要精确的场景,必须人工核对当年的放假安排,把节假日和调休都考虑进去。
怎么选对口径
面对一个「算天数」的需求,建议按这个顺序判断。
先问「按天还是按时长」。如果是按天(请假、工期、账期),用自然日;如果是按时长(运行多久、间隔多长),用总天数。
再问「算不算首尾」。请假、住院这类通常包含结束当天;「隔了几天」这类通常不包含。
最后问「要不要排除周末」。涉及工作安排时用工作日,其他场景用自然日。
这三个问题的答案组合起来,就能确定该看工具里的哪一个数值。工具通常会同时给出这几个口径,因为不同场景需要不同答案——关键是使用者知道自己在看哪一个。
检查清单
- 总天数是精确时长换算,结果是小数,反映实际经过的时间
- 自然日数只比较日历日期,忽略具体时刻,今天到明天就是 1 天
- 请假、工期、账期用自然日;运行时长、执行耗时用总天数
- 「包含结束当天」勾选后自然日加 1,两种口径差 1 天
- 工作日只排除周末,不含法定节假日与调休,只能粗略估算
- 选择口径时依次确认「按天还是按时长」「算不算首尾」「要不要排除周末」