周数字计算器

按 ISO 8601 规则算出某个日期属于年第几周(形如 2026-W37),并给出这一周周一到周日的具体日期、ISO 星期几与年内第几天。跨年周与 53 周年份都按标准处理。

ISO 周序号—
ISO 星期(周一=1)—
本周一—
本周日—
年内第几天—
所属季度—
ISO 周年(第 1 周的归属年)—
该 ISO 年共几周—

规则:ISO 8601 规定周一为一周之首,含该年 1 月 4 日(星期四)的那一周为第 1 周。日期支持 YYYY-MM-DD、YYYY/MM/DD、YYYY.MM.DD 三种分隔符。

2026 年逐月 15 日的周次对照表(默认 12 行)
日期ISO 周序该周周一年内天季度
2026-01-152026-W032026-01-12151
2026-02-152026-W072026-02-09461
2026-03-152026-W112026-03-09741
2026-04-152026-W162026-04-131052
2026-05-152026-W202026-05-111352
2026-06-152026-W252026-06-151662
2026-07-152026-W292026-07-131963
2026-08-152026-W332026-08-102273
2026-09-152026-W382026-09-142583
2026-10-152026-W422026-10-122884
2026-11-152026-W462026-11-093194
2026-12-152026-W512026-12-143494

使用方法

  1. 在「目标日期」填日期,默认示例 2026-09-07。三种分隔符都认:2026-09-07、2026/09/07、2026.09.07。
  2. 在「对照年份」填年份,默认 2026。下方对照表会按这个年份的 12 个月逐月给出周次;改成 2027 可以看跨年周的变化。
  3. 点「计算周次」或按 Enter。结果区 8 格给出 ISO 周序、ISO 星期、本周一、本周日、年内天、季度、ISO 周年与该年总周数。
  4. 把目标日期改成 2027-01-01 试一次:它会输出 2026-W53 而不是 2027-W01,这是本页最容易被算错的一处。
  5. 「加载更多」每次多给 12 行;「导出 CSV」带 UTF-8 BOM,Excel 打开不乱码。

这个周数字计算器能解决什么

把「年度第几周」算准。ISO 8601 的周序不是简单除以 7——它以周一为起点、以「含 1 月 4 日的那周」为第 1 周,跨年时周序会与日历年脱钩。2027-01-01 属于 2026 年的最后一周,这个事实用 Math.ceil(天数 / 7) 永远算不出来。

对齐周报、周报排期与迭代周期。研发团队的「第 37 周」几乎都用 ISO 口径,因为 ISO 周在全球范围内(含美国)都是统一的,而美式 %U / %W 只在美国使用。

核对报表口径。财务与运营报表常按 ISO 周聚合,同一份数据在 Excel 里用 WEEKNUM 与用 ISO 口径可能差一周,尤其在年末年初;周数字计算器给出确定的答案与所在周的起止日期。

查某个 ISO 年到底有 52 周还是 53 周。2026 年有 53 周,2027 年只有 52 周,做年度周次规划时这个差别会直接影响到「第 53 周有没有」的排期问题。

本页只算 ISO 8601 周序,不算孕周、不算两个日期间隔的天数。需要日期间隔请用日期间隔天数计算器;需要两个日期相差多少个月请用日期差值计算器;需要从今天往前数天数用距今天数计算器。

原理与规则说明

核心算法四行,用的是 Date.UTC 加 getUTCxxx,全程不碰本地时区:

dayNum = (d.getUTCDay() + 6) % 7 算出「周内第几天」(周一=0 到周日=6);d.setUTCDate(d.getUTCDate() - dayNum + 3) 把日期挪到本周四;该周四所在的公历年就是 ISO 周年;周数等于 1 + Math.round((本周四 − 第 1 周的周四) / 7 天)。

为什么用「本周四」而不是本周一。ISO 8601 的判定是「第 1 周是含该年 1 月 4 日(星期四)的那一周」——1 月 4 日必定落在周四,所以「含 1 月 4 日的那一周」等价于「含 1 月 4 日所在周四的那一周」。把日期统一挪到本周四之后,跨年的两个日期(2026-12-31 与 2027-01-01)会自然落到同一周里,归属问题一次解决。

为什么必须用 UTC 而不是本地时间。new Date('2026-09-07') 按 ES5 规范被当作 UTC 午夜解析,而 getDay() 返回的是本地时区的星期,两种混用会在东八区产生一天的偏差。本页统一用 Date.UTC(y, m, d) 构造,再全部用 getUTCxxx 读取,任何时区都得到同一个结果,夏令时也不会影响。

为什么不能直接用 getDay() + 1。JavaScript 的 getDay() 里周日是 0、周一是 1,而 ISO 要求周一是 1、周日是 7。直接 +1 会把周日算成 1、周一算成 2,整周错位一天。必须 (getDay() + 6) % 7 + 1 转一次。

周数取整用 Math.round 而不是 Math.floor。两个周四之间相差整数周,用 Math.floor 在遇到负差值时(如目标日在第 1 周之前)会向下多取一周;实测默认示例 2026-09-07 落在 2026-W37,两种取整在这个例子上结果相同,但换成 2019-12-30 这类日期就能看出差别。

年份范围限 1900 ~ 2100。下限不只是业务考虑:Date.UTC(99, 0, 1) 会把 99 映射成 1999(实测返回 1999-01-01),0~99 年这段必须靠 setUTCFullYear() 修正,不如直接不接受。1900-02-29 在 JavaScript 的 Date 里不存在,会被自动进位成 1900-03-01,所以页面必须做往返校验。

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

默认示例 2026-09-07(周一)的八格实测:

跨年边界的三组实测对照,这是本页最该记住的部分:

53 周年份的判定规则是:1 月 1 日是周四,或者 1 月 1 日是闰年且为周三。实测 2020 年(闰年,1 月 1 日周三)53 周、2026 年(1 月 1 日周四)53 周,其余 2021~2025、2027、2028 均为 52 周,8 个样本全部与规则预测一致。

下方对照表是 2026 年逐月 15 日的周次:1 月 15 日 W03、6 月 15 日 W25(这天恰好是周一,是全年唯一「15 日正好是周一」的月份)、12 月 15 日 W51。年内天从 15 递增到 349。

输入范围与对照表

设置项可选范围本页默认值作用与限制
目标日期1900-01-01 ~ 2100-12-312026-09-07三种分隔符;越界与非法日期都报错
对照年份1900 ~ 21002026只影响下方对照表,不影响周次计算
日期分隔符- / / / .-用正则统一匹配后拆分
周首日固定为周一周一ISO 8601 规定,不提供切换
表格行数固定 12 行12按 12 个月各取 15 日

为什么周首日不做成下拉框。周一为周首是 ISO 8601 与 GB/T 7408 的硬性规定,做成可切换的选项等于允许生成「非 ISO 的 ISO 周序」,那不如不加。美国口径的周序(%U 周日起、%W 周一起)本可以在此提供,但它们不是本页要解决的问题,放进去只会让「周数字」这个输出变得含糊。

对照表按「每个月的 15 日」取值,是为了让 12 行覆盖全年又不重复。15 日在每个月都存在,2 月也一样,不需要为短月做特殊处理。

输入范围、边界与精度说明

非法日期必须做往返校验。Date 不做日历校验:new Date(Date.UTC(2026, 1, 30)) 会静默进位成 2026-03-02,Date.UTC(1900, 1, 29) 会得到 1900-03-01。所以页面先用正则 ^(\d{4})[-/.](\d{1,2})[-/.](\d{1,2})$ 匹配,再把年月日构造成 Date,最后把结果格式化回字符串与输入比对——不一致就说明日期不存在,报「第 N 月没有 29 日」这类具体错误。

年份下限 1900 的原因前面讲过:Date.UTC() 对 0~99 年有到 19xx 的映射(实测 Date.UTC(99, 0, 1) = 1999-01-01),必须用 setUTCFullYear() 才能修正。上限 2100 是为了给日期控件与业务场景留够余量。Date 本身用 8 字节双精度存毫秒,理论范围约 ±27 万年,不受 32 位时间戳 2038 问题影响,所以 2100 这个上限纯粹是可用性考虑。

闰年判定要按公历完整规则:(y % 4 === 0 && y % 100 !== 0) || y % 400 === 0。1900 能被 100 整除但不能被 400 整除,是平年,2 月只有 28 天;2000 能被 400 整除,是闰年。ISO 周年与公历年的天数差正是由这个规则决定的,它间接影响 53 周的判定。

常见误用一:以为周序等于「年内第几天除以 7 向上取整」。2026-01-01 是第 1 天,除 7 向上取整是第 1 周没错;但 2026-01-04 是第 4 天,除 7 得第 1 周,而它其实属于 2026-W01 的周四——看似一致;真正暴露问题的是 2027-01-01:第 1 天除 7 得第 1 周,但 ISO 答案是 2026-W53,差 52 周。

常见误用二:用 Excel 的 WEEKNUM 对齐。Excel 的 WEEKNUM 默认参数 return_type=1 是「周日为一周之首」,与 ISO 不同;要对齐得用 ISOWEEKNUM()(Excel 2013 以后提供)。2027-01-01 在默认口径下是第 1 周,在 ISO 下是 2026-W53。

常见误用三:把本页当成孕周或孕产期计算。本页是日历周序,不涉及任何医学口径。孕期相关的问题请用专门的孕产期工具,并遵循医生意见。

常见问题

为什么 2027-01-01 算出来是 2026-W53?

因为 ISO 8601 规定第 1 周是「含该年 1 月 4 日(星期四)的那一周」。2027-01-04 是周一,它所在的那一周从 2027-01-04 开始,才是 2027-W01;而 2027-01-01(周五)落在前一周,该周的周四是 2026-12-31,属 2026 年,所以归 2026 年的最后一周。2026 年恰好有 53 周,这个位置就是 W53。

怎么知道某一年是 52 周还是 53 周?

两条规则满足其一即是 53 周年:1 月 1 日是周四,或者 1 月 1 日是闰年且为周三。实测 2020 年(闰年、1 月 1 日周三)和 2026 年(1 月 1 日周四)都是 53 周,2021~2025、2027、2028 都是 52 周。本页结果区最后一格会直接告诉你该年共几周。

结果会不会因为我在东八区或别的时区而变?

不会。页面全程用 Date.UTC 构造日期、用 getUTCxxx 读取,不调用本地时区的 getDay()。这是必须的——new Date('2026-09-07') 按规范被当作 UTC 午夜解析,而 getDay() 返回本地星期,混用会在东八区偏一天。

2026-02-30 这样不存在的日期会怎么处理?

会报错而不是自动进位。Date 本身不校验日历,Date.UTC(2026, 1, 30) 会静默变成 2026-03-02。页面做完正则匹配后会再把日期格式化回字符串与输入比对,不一致就提示「2026 年 2 月没有 30 日」这类具体错误。1900-02-29 同理会被拦下。

为什么年份下限是 1900 而不是 1?

因为 Date.UTC(99, 0, 1) 会把 99 当成 1999,返回 1999-01-01;必须先 setUTCFullYear(99) 才能得到 0099-01-01。年份小于 100 时每一步都要额外修正,容易出错,不如把 1900 作为下限。ISO 规则本身对更早的年份仍然成立,只是没有实际使用场景。

ISO 周序和美国 %U / %W 差在哪?

差在两点。一是周首日:%U 以周日为首、%W 以周一为首,ISO 固定周一。二是第 1 周的起点:ISO 要求「含 1 月 4 日」的那周,%U / %W 只从 1 月 1 日所在周算起,允许第 1 周只有 1 天。最典型的差异:2027-01-01 在 ISO 下是 2026-W53,在 %U 与 %W 下都是第 01 周,差 52 周。

「年内第几天」和周序有关系吗?

没有直接关系。年内第几天是从 1 月 1 日起数的自然日位置,跨年时它会在 1 月 1 日重置为 1;而 ISO 周序跟着 ISO 周年走,可能归属上一年。2027-01-01 的年内第几天是 1,但周序是 2026-W53——两个数字来自两套独立计数,不能互相换算。

这个页面会上传我输入的日期吗?

不会。解析用正则,计算用 Date.UTC 与 getUTCxxx,模板里没有任何 fetch 或 XMLHttpRequest。可以在开发者工具的 Network 面板确认:页面加载后除自身 CSS 外不再发出任何请求,刷新即清空。

相关工具

周数字计算器只做 ISO 8601 周序这一个换算,下面这些页面处理其它时间口径的问题,跨年与闰年场景常需要交叉核对。