使用方法
- 「入职日期」默认已经填好 2016-03-15,你可以改成自己的入职日;「计算基准日」留空表示用今天,填了某个日期就按那个日期结算。
- 点「计算」,或在任意一个日期框里按回车完成计算。
- 结果以四张结论卡片呈现:已工作天数、工龄(年/月/日)、下次周年日期、距下次周年天数;下面一块是同样的结论原文,可直接复制。
- 「复制结论」复制四张卡片的纯文本;「复制周年表」复制逐年周年表的制表符分隔文本,粘进表格即自动分列。
- 下方「逐年周年表」默认显示前 10 行,点「加载更多」展开到 30 行;「导出 CSV」存成带字节序标记的文件,Excel 打开不乱码。
- 本页不联网、不写 localStorage,刷新即恢复默认;计算全部在本地完成。
- 入职日期晚于计算基准日、或早于 1970-01-01(Unix 纪元)都会给出具体提示,不静默返回空。
- 闰日(2 月 29 日)入职的人,非闰年没有 2 月 29 日,本页采用「顺延到下一个闰年」的口径,并在表里自然缺位。
这个工作周年计算器能解决什么
工龄、司龄、周年纪念这类问题看起来只是减法,真正动手算容易在三个地方栽跟头。第一是时区:本机是 UTC+8,用本地 new Date(年,月,日) 再取 toISOString() 会因为时区回退而差一天,月底与闰日尤其明显。第二是月日借位:算「10 年 7 个月 10 天」时,借位的那个月到底是 28 天还是 31 天,差一天工龄就错位。第三是闰日入职:2020-02-29 入职的人,2021 到 2023 这三年都没有 2 月 29 日,周年到底算哪天必须说清。
本页把这三类坑都按确定口径处理:天数差一律走 Date.UTC,工龄用「先整年、再整月、最后余天」的三段式并逐月借位,闰日入职者只在闰年才确认周年、其余年份顺延。这样 2016-03-15 到 2026-10-25 稳定得到「10 年 7 月 10 天」,2020-02-29 到 2026-10-25 稳定得到「6 年 7 月 26 天」,不随运行环境漂移。
边界也要说清:本页只做日期算术,不连 HR 系统、不读档案、不判断合同类型。司龄常指在同一家单位的连续年限,与「工龄」在跳槽场景下可能不同,本页默认按你填的入职日算连续工龄,需要算司龄请填当前单位的入职日。
计算原理与变量说明
天数差的核心只有一行:Math.round((Date.UTC(年2,月2-1,日2) - Date.UTC(年1,月1-1,日1)) / 86400000)。用 UTC 而不是本地时间,是为了排除时区对端点日期的偏移——本机 UTC+8 下,new Date(2023,1,29) 在本地是 2023-03-01,但 toISOString() 会退回成 2023-02-28,因为 UTC 的零点落在前一天的 16:00。用同一步时区,两个端点都按 00:00 UTC 取整,差值才稳定。
工龄的年/月/日用三段法:从入职年月起,逐年加 1 直到「再加一年就超过基准日」,得到整年数;再逐月加 1 直到「再加一月就超过」,得到整月数;剩下的天数用基准日减去「整年整月之后那一天」的 UTC 差。借位时哪个月小,就按那个月的实际天数(1 月前是 12 月 31 天,3 月前是 2 月 28 或 29 天)。逐月加一时借助 Date.UTC 自身的溢出行为:Date.UTC(2023,1,29) 在平年自动落到 3 月 1 日,与 JS 的既定语义一致,本页照单全收并在正文明说。
下次周年从入职次年起逐年试探:对每一年 Y,构造 Date.UTC(Y, 入职月-1, 入职日),若构造结果里的月份或日期与预期不符,说明这一年没有这一天的合法日期(典型就是 2 月 29 日在平年溢出到 3 月 1 日),跳过该年;否则它就是候选,取第一个晚于基准日的候选。精核实例:2016-03-15 入职,下一个晚于 2026-10-25 的周年是 2027-03-15;2020-02-29 入职,2026、2027 都因平年溢出被跳过,落到 2028-02-29。
10000 天约等于 27.3791 年(除以 365.2425 的回归年长度),可作为「万天纪念」的粗略参照,本页不直接标万年节点,但你能在周年表里数到。
| 变量 | 含义 | 取值 | 影响 |
|---|---|---|---|
| hire | 入职日期 | 1970-01-01 起 | 工龄与周年的起点 |
| base | 计算基准日 | 留空=今天 | 所有结果都相对它 |
| days | 已工作天数 | 非负整数 | UTC 差四舍五入 |
| ymd | 工龄年/月/日 | 三段整数 | 逐月借位得出 |
| next | 下次周年 | YYYY-MM-DD | 闰年顺延处理 |
完整示例
默认入职日 2016-03-15,基准日用今天(2026-10-25)演示。已工作天数 = 两个端点的 UTC 差 ÷ 86400000 再四舍五入,得到 3876 天;工龄从 2016-03-15 起先数整年:到 2026-03-15 满 10 年,再把 2026-03-15 到 2026-10-25 拆成 7 个月又 10 天,合计 10 年 7 月 10 天;下次周年从 2026 年起试,2026-03-15 已过、2027-03-15 未到,取 2027-03-15;距下次周年就是 2026-10-25 到 2027-03-15 的 141 天。
2016-03-15 入职 · 基准 2026-10-25 已工作天数 = 3876 天 工龄 = 10 年 7 月 10 天 下次周年 = 2027-03-15 距下次 = 141 天
把「入职日期」改成 2020-02-29 再算:整年推进到 2026 年是 6 年(2021~2023 没有 2 月 29 日,整年确认只在闰年落地),余数部分是 7 个月 26 天,合计 6 年 7 月 26 天,已工作 2430 天;下次周年跳过 2026、2027 两个平年,落到 2028-02-29,距下次 492 天。把「计算基准日」填成 2020-03-01,则按那个历史节点结算,工龄会短一大截,方便回看当年。
逐年周年表
下表列出入职次年起连续 30 个周年的日期与「距基准日天数」,由页面自己的算法逐行算出,前 10 行直接展开,点工具区的「加载更多」看余下 20 行。正值表示已过去多少天,负值表示还有多少天到来;闰日入职的年份在表里自然缺位,不会硬凑一个不存在的 2 月 29 日。
| 第 N 周年 | 日期 | 距基准日(天) |
|---|---|---|
| 1 | 2017-03-15 | 3511 |
| 2 | 2018-03-15 | 3146 |
| 3 | 2019-03-15 | 2781 |
| 4 | 2020-03-15 | 2415 |
| 5 | 2021-03-15 | 2050 |
| 6 | 2022-03-15 | 1685 |
| 7 | 2023-03-15 | 1320 |
| 8 | 2024-03-15 | 954 |
| 9 | 2025-03-15 | 589 |
| 10 | 2026-03-15 | 224 |
| 11 | 2027-03-15 | -141 |
| 12 | 2028-03-15 | -507 |
| 13 | 2029-03-15 | -872 |
| 14 | 2030-03-15 | -1237 |
| 15 | 2031-03-15 | -1602 |
| 16 | 2032-03-15 | -1968 |
| 17 | 2033-03-15 | -2333 |
| 18 | 2034-03-15 | -2698 |
| 19 | 2035-03-15 | -3063 |
| 20 | 2036-03-15 | -3429 |
| 21 | 2037-03-15 | -3794 |
| 22 | 2038-03-15 | -4159 |
| 23 | 2039-03-15 | -4524 |
| 24 | 2040-03-15 | -4890 |
| 25 | 2041-03-15 | -5255 |
| 26 | 2042-03-15 | -5620 |
| 27 | 2043-03-15 | -5985 |
| 28 | 2044-03-15 | -6351 |
| 29 | 2045-03-15 | -6716 |
| 30 | 2046-03-15 | -7081 |
结果边界与错误提示
- 入职日期格式不是合法日期时,提示「入职日期「X」不是合法日期(应为 YYYY-MM-DD)」,并把原值引出来;2 月 30 日这类不存在的组合也会被这一步拦下。
- 「计算基准日」填了非法值时,同样提示「基准日「X」不是合法日期」,不会退回 1970 年。
- 入职日期晚于基准日时,提示「入职日期不能晚于计算基准日:入职 X 晚于基准 Y」,拒绝输出负工龄。
- 入职日期早于 1970-01-01(Unix 纪元)时,提示「入职日期不能早于 1970-01-01」,因为底层时间戳无法表示更早的日期。
- 入职日期被清空时提示「入职日期这一栏是空的,请填写入职日期」,不会输出 NaN。
- 闰日入职者在平年没有合法周年日,页面顺延到下一个闰年,表里相应年份自然缺位,不补 2 月 28 日。
- 基准日留空时用浏览器当前日期,因此「已工作天数」每天加一、倒计时每天减一,这是预期行为,不是 bug。
- 导出的 CSV 带字节序标记,复制到剪贴板的周年表是制表符分隔,两者都方便直接进表格软件。
常见问题
为什么不直接用两个日期相减?
因为相减用到的是本地时间,本机 UTC+8 下端点会被时区回退。直接用 new Date(2023,1,29) 得到本地 2023-03-01,但 toISOString() 又退回成 2023-02-28,前后差一天。本页改用 Date.UTC 把两个端点都按 00:00 UTC 取整,差值才稳定。
工龄的年/月/日是怎么算的?
用三段法:从入职年月起逐年加 1,直到再加一年就超过基准日,得到整年数;再逐月加 1,直到再加一月就超过,得到整月数;最后用基准日减去「整年整月之后那一天」的 UTC 差得到余天。借位时按上一个月的实际天数,1 月前是 12 月 31 天,3 月前是 2 月 28 或 29 天。
2 月 29 日入职,平年的周年算哪天?
本页采用「顺延到下一个闰年」口径:平年没有 2 月 29 日,周年跳过该年,落到下一个闰年。2020-02-29 入职时,2026、2027 都是平年,下一次合法周年是 2028-02-29,距离 492 天。部分 HR 系统会取 2 月 28 日,口径不同,请按所在单位规则判断。
工龄和司龄是一回事吗?
不一定。工龄常指从某次入职起算的连续工作年限,司龄特指在同一家单位的连续年限,跳槽后两者会出现差异。本页只按你填的入职日算连续工龄,不连 HR 系统,也不判断合同归属。
基准日留空为什么会变?
留空时页面用浏览器的当前日期作基准,所以「已工作天数」每天加一、下次周年倒计时每天减一,这是预期行为。要锁定某个历史节点回看,请在「计算基准日」里填具体日期。
表里为什么有负数?
负数是还没到来的周年,表示「距今还有多少天」。前 10 行通常是已过的周年(正数),展开后的后 20 行大多是未来节点(负数)。正值表示已过去多少天,负值表示还有多少天到来。
10000 天是多久?
约 27.3791 年,按回归年长度 365.2425 天折算。本页不直接标「万天纪念」,但你可以在逐年周年表里配合已工作天数推断对应的节点。
导出的文件带 BOM 吗?
CSV 导出带字节序标记,Excel 打开不乱码;复制到剪贴板的周年表是制表符分隔文本,粘进表格软件即自动分列。两者都不含任何个人数据,纯本地计算。