日期差值计算器

把两个日期算成「36 年 4 月 11 天」这样能直接写进合同和简历的跨度,同时给出总天数、整周数与零头,并能反推指定天数之前或之后是几月几号。

反向推算表:以结束日期为基准,逐个偏移天数求出前后的具体日期
偏移天数 N向前 N 天向后 N 天该日星期

提示:三个输入框里任意一个按 Enter 都会立即重算;「复制对照表」复制的是 TSV,粘进 Excel 会自动分成四列;「导出 CSV」带 UTF-8 BOM,Excel 打开不会乱码。

使用方法

这个日期差值计算器只有三个输入框——开始日期、结束日期、偏移天数 N,结果随输入自动重算,不需要点按钮,也不会向服务器发任何请求。

  1. 在「开始日期」填 1990-05-20(示例值),在「结束日期」填 2026-10-01(示例值)。两个框都能直接点日历图标挑,也能手动键入;先发生的那天必須放开始日期。
  2. 页面打开时已经按这两个示例日期算过一遍,结果卡第一格就是 36 年 4 月 11 天——这是本页的主输出,也是能直接写进合同、简历、工龄说明的写法。
  3. 第二格给总天数 13283 天,第三格把它拆成 1897 周 4 天。按月汇报、按周汇报、按天汇报三种口径一次到手,不用自己再换算。
  4. 「偏移天数 N」默认 10000,用来做反向推算:结果卡会同时给出结束日期往前 10000 天是 1999-05-16、往后 10000 天是 2054-02-16。想看一年前后就把 N 改成 365。
  5. 下方「反向推算表」把 20 组常用天数一次列出,默认先显示前 12 行,点「加载更多」补齐剩下的 8 行;点「复制对照表」按 TSV 复制、「导出 CSV」下载带 BOM 的文件。
  6. 只想算「到今天多少天」,点一下「结束日期取今天」,结束日期会换成系统当天再重算一遍。

日期差值计算器能解决什么问题

一是把天数翻译成人能读的跨度。社保缴费 13283 天、设备折旧 3652 天、仓库账龄 1500 天,这些数字单独看没有时间感,换成「36 年 4 月 11 天」「10 年」「4 年 1 月 8 天」之后,汇报和写材料都能直接用。

二是算清含首日与不含首日的争议。工期、保修期、试用期这类条款经常在「算不算第一天」上扯皮。本页给的是两端都不含的纯时间差:同一日期差 0 天,相邻两天差 1 天,规则唯一,争议点被消掉。

三是按周汇报的整数拆解。敏捷迭代、租赁周、产线周报要的是「多少个整周外加几天」,本页的第三格直接给出 1897 周 4 天,比 1897.57 周这种小数好写也好核对。

四是反推某个天数对应的是哪天。合同写「交付后 1000 天内完成验收」、活动写「上线 365 天回访」,把天数填进「偏移天数 N」就能立刻看到具体日期,配合推算表还能一次比对 20 个节点。

本页不做这些事:不排除周末和法定节假日(要这个请用页面底部的「工作日计算器」),不做时区换算与时间戳解析,不做倒计时与提醒,也不算「两个日期之间有多少个某星期几」。要按秒、毫秒量级换算请用时间戳转换工具。

计算原理:借位法、UTC 午夜与三个中间量

核心只有两步:把日期换成毫秒时间值相减得到总天数,再用按月加、日钳位的借位法求出「年 / 月 / 天」。第二步是本页与常见的「总天数 ÷ 365」做法最大的区别。

第一步调用的是 Date.prototype.getTime() 的 UTC 毫秒时间值。每个日期先通过 setUTCFullYear(y, m - 1, d) 归一化到当天 UTC 零点,再取毫秒值相减,除以 86400000 得到天数。这里刻意用 UTC 而不是本地时间:中国大陆在 1986 年至 1991 年实行过夏令时,本地午夜相减会出现 23 小时或 25 小时的天,除以一天会得到 0.958 或 1.042 这种小数;UTC 没有夏令时,差值永远是 86400000 的整数倍。

第二步的借位法是这样走的。先算两个日期的月份差 n = (年差 × 12) + 月差,把开始日期加 n 个月(遇到目标月没有该日就钳到月末,例如把 1 月 31 日加 1 个月得 2 月 29 日),如果加完还超过结束日期就把 n 减一,直到不超过为止。剩下的零头再用毫秒差算天数,最后把 n 拆成 Math.floor(n / 12) 年和 n % 12 月。这套「按月加、日钳位」的口径与 moment.js、dayjs 的 diff 一致,所以 2024-01-31 到 2024-03-01 得到的是 1 个月 1 天,而不是 1 个月 −1 天这种负数结果。

三个中间量依次是:①两个 UTC 毫秒时间值 t1、t2;②总天数 Math.round((t2 - t1) / 86400000);③最大整数月数 n 与剩余天数。三个量互相可以校验——把 13283 天除以 7 得 1897.57,与「1897 周 4 天」完全对得上。

完整示例(数字由页面算法实算)

示例条件就是页面打开时的默认值:开始日期 1990-05-20、结束日期 2026-10-01、偏移天数 10000。实测输出如下:

再拿几个容易吵起来的用例核对一遍口径:2024-01-31 → 2024-03-01 得到 0 年 1 月 1 天(共 30 天),因为 1 月 31 日加 1 个月被钳到 2 月 29 日,再走 1 天;2024-02-29 → 2025-02-28 得到 1 年 0 月 0 天(共 365 天),因为加满 12 个月正好钳到 2 月 28 日;2024-01-01 → 2025-01-01 同样显示 1 年 0 月 0 天,但总天数是 366 天。也就是说「1 年 0 月 0 天」既可能是 365 天也可能是 366 天,跨度写法必须和总天数一起看。

输入范围与常见区间对照表

下表用同一套算法把 12 个常用区间算了一遍,第一行就是页面默认示例。做月报、做合同测算时可以直接查表;要换成别的日期,把值填进上面的输入框即可。

区间总跨度总天数整周数与零头
1990-05-20 → 2026-10-01(默认)36 年 4 月 11 天13283 天1897 周 4 天
2025-03-01 → 2026-03-01(平年整 1 年)1 年 0 月 0 天365 天52 周 1 天
2024-01-01 → 2025-01-01(闰年整 1 年)1 年 0 月 0 天366 天52 周 2 天
2026-01-01 → 2026-04-01(一个季度)0 年 3 月 0 天90 天12 周 6 天
2026-09-01 → 2026-10-01(一个月整)0 年 1 月 0 天30 天4 周 2 天
2026-09-24 → 2026-10-01(一周整)0 年 0 月 7 天7 天1 周 0 天
2016-10-01 → 2026-10-01(10 年)10 年 0 月 0 天3652 天521 周 5 天
2006-10-01 → 2026-10-01(20 年)20 年 0 月 0 天7305 天1043 周 4 天
1996-10-01 → 2026-10-01(30 年)30 年 0 月 0 天10957 天1565 周 2 天
1976-10-01 → 2026-10-01(50 年)50 年 0 月 0 天18262 天2608 周 6 天
1926-10-01 → 2026-10-01(100 年)100 年 0 月 0 天36525 天5217 周 6 天
1900-01-01 → 2100-01-01(200 年)200 年 0 月 0 天73049 天10435 周 4 天

表里最有意思的是最后三行:同样写「10 年 0 月 0 天」,总天数却分别是 3652、7305、10957。原因是平年 365 天、闰年 366 天,平均一年 365.2425 天(格里历 400 年共 146097 天、含 97 个闰年),所以 按年数乘 365 永远会少算:十年少 2 天、三十年少 7 天、二百年少 49 天。

结果边界、舍入与闰年规则

下面的数字是刻意定的边界,知道它们能避免把这一页用在它管不到的地方:

常见问题

为什么「1 年 0 月 0 天」有时是 365 天、有时是 366 天?

因为跨度的「年 / 月」是按日历借位算的,而总天数是按实际日历天数加的。2024-01-01 到 2025-01-01 跨过 2024-02-29,所以是 366 天;2025-03-01 到 2026-03-01 没跨到 2 月 29 日,就是 365 天。两者都写作 1 年 0 月 0 天。写合同时要避免歧义,最佳做法是同时写上跨度与总天数。

输入框里的日期手动键错了会怎样?

会给出具体报错而不是静默归零。工具要求格式为 YYYY-MM-DD,年份在 1900–2100 之间,并且会回读校验:填 2024-02-30 这类不存在的日期会被拦下,因为 JavaScript 会把它滚成 3 月 1 日,回读时月份或日号对不上。空值、只填年份、以及开始日期晚于结束日期,都会各自给出对应提示。

为什么不直接写「相差多少天」就够了?

因为天数无法表达跨度。13283 天可以是任何长度的区间,而「36 年 4 月 11 天」能立刻看出量级;反过来,跨度的「年 / 月」在借位处会有歧义(1 月 31 日到 3 月 1 日算 1 个月 1 天还是 0 个月 30 天),天数则没有歧义。两套口径各有用途,所以本页同时给出,而不是二选一。

2024-01-31 到 2024-03-01 为什么不是「1 个月 0 天」?

因为 1 月 31 日加 1 个月,2024 年是闰年,目标 2 月没有 31 日,会被钳到 2 月 29 日;从 2 月 29 日到 3 月 1 日还剩 1 天,所以是 1 个月 1 天。若换成平年(2025-01-31 到 2025-03-01),钳位结果是 2 月 28 日,剩 1 天,跨度同样是 1 个月 1 天,但总天数从 30 天变成 29 天。

跨夏令时的地区会算错吗?

不会。所有运算都走 UTC 毫秒时间值,getUTCFullYear / getUTCDate 只读 UTC 字段,与本机时区无关。中国大陆 1986–1991 年实行过夏令时,用本地时间相减会出现 23 或 25 小时的天;本页从源头避开了这个坑,因此在任何时区的浏览器里结果都一致。

能把结果当成「还剩多少天」的倒计时吗?

可以作为天数来源,但它不含倒计时逻辑,也不会自动刷新到今天。要做倒计时或提醒,请用页面底部的「天倒计时计算器」;要算「距今多少天」,把结束日期设成今天即可,页面上有「结束日期取今天」按钮可以一键完成。

为什么不算工作日,也不排除节假日?

因为日历差值和排班是两件事:前者只跟日历有关,后者取决于周末定义、法定节假日名单和调休补班日。本页刻意只做前者,把后者留给专门的工作日工具,两边各自口子清晰,不会出现「同一个区间两个工具给出不同天数」的困惑。要排周末和节假日,请用页面底部的「工作日计算器」。

输入的两个日期会传到服务器吗?

不会。这个日期差值计算器全程只调用浏览器本地的 Date 对象,页面没有任何网络请求,也不写浏览器存储,刷新后输入框会回到默认的示例日期。想自己核实,打开开发者工具的 Network 面板,改几次日期看看有没有新请求发出即可。

相关工具