时间线生成

每行一条「日期 标题|备注」,解析、排序后输出带中文长日期与星期的时间线;日期全程走 Date.UTC 与 Intl.DateTimeFormat 的 UTC 口径,换台电脑打开也是同一天。

事件条数6
首日2024-01-15
末日2026-10-03
跨度992 天
排序升序
输出字符252
#1 2024-01-15 2024年1月15日(周一) 项目立项
#2 2024-06-30 2024年6月30日(周日) 原型验收
#3 2025-03-12 2025年3月12日(周三) 内测上线
#4 2025-11-05 2025年11月5日(周三) 正式发布
  备注:全渠道同步
#5 2026-04-20 2026年4月20日(周一) 用户破十万
#6 2026-10-03 2026年10月3日(周六) 第二版规划

跨度:2024-01-15 → 2026-10-03,共 992 天

文本框里按 Ctrl / Cmd + Enter 生成(Enter 单独按是换行);日期支持 2026-10-03、2026/10/3、2026.10.03、2026年10月3日 四种写法,标题与备注之间用半角 | 分隔。

使用方法

  1. 在事件列表里每行写一条事件,格式是「日期 空格 标题」,需要备注再接「|备注」。默认示例是 6 条产品里程碑,从 2024-01-15 项目立项 到 2026-10-03 第二版规划。
  2. 选排序方式:升序(默认)、降序或保持输入顺序。同一日期的多条事件在任何排序下都保持你输入的先后次序。
  3. 按 Ctrl/Cmd + Enter 或点「生成时间线」。结果区输出编号、ISO 日期、中文长日期、星期与标题;有备注的行会另起一行缩进展示。
  4. 看统计条里的跨度:它是首末两个日期的自然日差(不含首日),示例 6 条的跨度是 992 天。哪条是首日哪条是末日由日期决定,与排序方式无关。
  5. 「复制 Markdown」输出 - **2024-01-15** 项目立项 形式的列表,可直接贴进 README;「复制对照表」「导出 CSV」作用于下方的日期写法对照表。

这个时间线生成工具能解决什么问题

一是把流水账变成有序的时间线。项目复盘、产品迭代记录、投标业绩罗列、个人履历里的项目经历,原始材料几乎都是想到哪写到哪。这个时间线生成工具按日期重排后给出编号、长日期与星期,直接可贴进周报或文档。

二是解决「日期少一天」的诡异现象。用 new Date('2026-10-03') 解析日期再取 getDate(),在西半球的机器上会得到 2 号——因为 ECMAScript 规定 date-only 字符串按 UTC 零点解析,本地时区一减就退回前一天。本页从解析到显示全链路固定 UTC,同一份输入在任何时区生成同一份时间线,协作文档里不会出现两个人看到不同日期。

三是把不统一的日期写法收拢成一种。收集来的材料里 2026/10/3、2026.10.03、2026年10月3日 混在一起,工具统一解析后输出统一的 YYYY-MM-DD 与「2026年10月3日(周六)」两种口径,排序也才有依据。

四是提供能直接二次加工的 Markdown。时间线的最终去处往往是 Markdown 文档、Notion 或_issue 列表,「复制 Markdown」按钮输出标准列表项,标题加粗、备注跟在后面,不用再手动排版。

这个时间线生成工具不做日期差与工作日计算,两个日期之间隔多少个工作日请用「日期时间」分类的专门工具;也不做时间戳与本地时间的互转,那是另一套带时区的口径;更不做图表绘制——饼图、条形图、行图谱各自有专门的生成页。本页只负责把带日期的事件序列变成文本时间线。

原理与规则说明:UTC 口径、稳定排序与闰年校验

解析是手工正则,不走 Date.parse。每行先用 split('|') 拆出备注,再对标题段用 /^\s*(\S+)\s+(.*)$/ 拆出日期 token 与标题,日期 token 交给 /^(\d{4})[-\/.](\d{1,2})[-\/.](\d{1,2})$/ 或 /^(\d{4})年(\d{1,2})月(\d{1,2})日$/ 两把正则。之所以不用 new Date('2026-10-03'),是因为 ECMAScript 的 Date Time String Format 只保证 YYYY-MM-DD(月日两位)被按 UTC 解析,而 2026-10-3、2026/10/3 这类写法属于实现相关的回退分支,不同浏览器可能给出不同结果甚至 NaN。

组装用 Date.UTC(y, m-1, d),显示用 Intl.DateTimeFormat('zh-CN', { timeZone: 'UTC' })。入口是手工拆出的整数,出口固定 timeZone: 'UTC',整条链路里没有任何本地时区参与。长日期走 year:'numeric', month:'long', day:'numeric' 得到「2026年10月3日」,星期走 weekday:'short' 得到「周六」——月份名、星期名全部复用 CLDR 数据,不手写 ['日','一','二'…] 查找表,也天然支持将来切换语言。

排序用 Array.prototype.sort 加时间戳比较。比较函数是 x.t - y.t,其中 t 是 Date.UTC 得到的毫秒数,整数相减没有精度问题(日期范围 1900~2100 年,时间戳约 ±4.1e12,远小于 253)。ECMAScript 2019 起明确要求 sort 必须稳定,所以同一天的多条事件在升序、降序、保持原序三种模式下都不会被打乱输入时的相对顺序——这是拿时间线讲年表时的实际需求。

闰年与每月天数用「当月最后一天」反推。不手写 y%4==0&&(y%100!=0||y%400==0),而是看 new Date(Date.UTC(y, m, 0)).getUTCDate()——第 m 月的第 0 天就是上个月最后一天,让引擎自己处理大小月与闰年。实测:2024 年 2 月 29 天、2026 年 2 月 28 天、1900 与 2100 年 2 月都是 28 天(整百年需被 400 整除才是闰年),所以 2024-02-29 合法而 2026-02-29、2100-02-29 都会被拒绝。

跨度是天数差,不含首日。末日 − 首日 的毫秒差除以 86400000 后取整。示例首日 2024-01-15、末日 2026-10-03,跨度 992 天;含首尾则是 993 天。本页统一用不含首日的口径,因为「项目从立项到规划走了多久」的自然理解是差值。

输出的体积上限是刻意设计的。200 条事件 × 每条约 60 字符 ≈ 1.2 万字符,一次 textContent 赋值在一帧内完成;超过 200 条直接拒绝并提示拆分,而不是悄悄渲染一份要滚动很久的结果。

完整示例(数值仅作演示)

示例条件与页面打开时的默认值完全一致:6 条事件、按日期升序。复算结果如下:

结果区里的文本就是上面这份输出的原样,Markdown 口径则是:

- **2024-01-15** 项目立项
- **2024-06-30** 原型验收
- **2025-03-12** 内测上线
- **2025-11-05** 正式发布(备注:全渠道同步)
- **2026-04-20** 用户破十万
- **2026-10-03** 第二版规划

下面是 16 种常见日期写法在同一套解析器下的判定,前 12 行默认显示,点「加载更多」展开剩余 4 行:

输入写法判定解析结果星期说明
2026-10-03可解析2026年10月3日周六标准写法,月日两位
2026-10-3可解析2026年10月3日周六月日允许 1 位
2026/10/03可解析2026年10月3日周六斜杠分隔可用
2026.10.03可解析2026年10月3日周六点分隔可用
2026年10月3日可解析2026年10月3日周六中文年月日可用
2026-2-3可解析2026年2月3日周二1 位月日,输出统一补零
2024-02-29可解析2024年2月29日周四闰年成立
2100-12-31可解析2100年12月31日周五本页年份上限
2026-13-01拒绝——月份 13 超出 1~12
2026-02-30拒绝——2026 年 2 月只有 28 天
2026-04-31拒绝——4 月只有 30 天
1899-12-31拒绝——年份早于 1900

输入范围与对照表

输入项的范围与超限动作如下,右列是填错时结果区会显示的具体提示:

字段/情况允许范围超限或填错时的动作
事件列表1~200 行非空行空文本拒绝;超过 200 条拒绝并报出实际条数
日期写法YYYY-M-D、YYYY/M/D、YYYY.M.D、YYYY年M月D日 四种不可识别时报出第几行与原文,并列出四种支持写法
年份1900~2100越界时报出第几行与实际年份
月份1~12越界时报出第几行与实际月份
日1~当月天数不存在时报出该月实际天数,如「2026 年 2 月只有 28 天」
标题1~80 字符缺失或超长时报出第几行与实际长度
备注0~60 字符,可省略超长时报出第几行与实际长度
排序方式升序 / 降序 / 保持输入顺序下拉框只接受预设值;异常值回落到升序并提示

本页与日期、时间类兄弟工具的口径区隔:

需求本页的做法不该用本页的情况
把带日期的事件排成时间线正是本页做的事—
算两个日期差几天、几个工作日只给首末跨度(自然日差),不做工作日剔除需要工作日口径时用日期计算类工具
时间戳与日期互转不处理秒/毫秒时间戳涉及 Unix 时间戳时用时间戳类工具
展示某个时刻的本地时间刻意固定 UTC,避免本地时区参与要按时区显示时刻的场景不适用本页
同一天多条事件的先后保持输入顺序(稳定排序)—

边界与精度说明

常见问题

为什么别的工具算出来的日期会少一天,这里不会?

少一天的工具几乎都在某一步用了 new Date('2026-10-03') 然后按本地时间取值。ECMAScript 规定这种 date-only 字符串按 UTC 零点解析,机器时区是 UTC-5 时,本地时间还是 10 月 2 日晚上 7 点,getDate() 就成了 2。本页把日期拆成整数、用 Date.UTC 组装、用 timeZone:'UTC' 的 Intl.DateTimeFormat 显示,全程没有本地时区插手,结果与机器设置无关。

同一天的两条事件会不会被排序打乱?

不会。ECMAScript 2019 规定 Array.prototype.sort 是稳定排序,比较函数相等时保持原有顺序。示例里若再加一条 2025-11-05 发布会复盘,无论升序降序它都会排在「正式发布」后面。若担心运行环境太老,可以直接选「保持输入顺序」。

跨度 992 天是怎么算的?含首尾吗?

跨度 = 末日 − 首日的自然日差,即两个 Date.UTC 时间戳之差除以 86400000,不含首日。2024-01-15 到 2026-10-03 是 992 天;如果你要含首尾(例如「项目进行了 993 天」的口径),把结果加 1 即可。本页统一用差值口径,避免两种说法在页面里混用。

2026-02-29 明明格式对,为什么被拒绝?

格式对不等于日期存在。2026 年不是闰年,2 月只有 28 天,所以 2026-02-29 会被拒绝并提示该月实际天数;2024-02-29 则正常解析。判断方式不是手写 %4 公式,而是看 Date.UTC(2026, 2, 0) 的日值——第 3 月的第 0 天即 2 月最后一天,整百年如 2100(非闰年)也自动正确。

一行里能写多个备注吗?

不能。备注只取第一个 | 之后的整段,后面再出现 | 会被忽略并提示。这样设计是因为时间线是「一事件一备注」的结构,多列数据应该拆成多行,而不是把标签、负责人、状态都塞进一个备注字段里。

能导入 Excel 里的日期吗?

可以,但要注意 Excel 常把日期存成 2026/10/3 或带时刻的 2026/10/3 0:00。前者本页直接支持;后者行首 token 是 2026/10/3、标题会被解析成 0:00,需要先删掉时刻列再粘贴。带千分位引号或合并单元格的表格,先另存为 CSV 再复制日期与标题两列。

为什么某一行写错了,整份时间线都不出了?

故意的。若只跳过错误行,你拿到的时间线会悄悄少几条,事后很难发现少了什么;本页选择整次拒绝,并把每一行的行号、原文、错因列出来,改完再生成一次即可。错误信息会具体到「第 3 行开头的『xx』不是可识别的日期写法」这种粒度。

输出能直接贴进 Markdown 文档吗?

「复制 Markdown」按钮输出的就是标准列表项:- **2024-01-15** 项目立项,带备注时追加「(备注:xxx)」,直接粘进 README、Issue 或 Notion 都能正常渲染加粗。结果区里的带编号版本更适合贴进聊天窗口或邮件正文,两种口径随取随用。

相关工具