今天到底是星期几?从数组遍历到 JavaScript 时区边界
我网站上有一道入门练习:把星期一到星期日放进数组,用循环逐行显示。题目很短,却包含一个容易忽略的区别:打印七个星期名称,只能说明程序遍历了数组,不能证明它知道今天是星期几。
本文从这道练习出发,重新用 JavaScript 实现,并补上真实页面需要处理的星期索引、时区和无效输入。原题使用 foreach;这里是新的 JavaScript 实现,不是把 PHP 代码直接改几个单词。
一、先把“展示列表”与“读取今天”分开
如果需求只是展示一周,数组和循环已经足够。下面的代码在浏览器控制台或 Node.js 中都能运行:
const mondayFirst = [
'星期一', '星期二', '星期三', '星期四',
'星期五', '星期六', '星期日'
];
for (const label of mondayFirst) {
console.log(`星期标签:${label}`);
}
这段程序会输出七行。它没有读取系统时间,也没有判断日期,所以我把输出前缀写成“星期标签”。如果七行都写“今天是”,读者容易误以为程序正在获取日期;这就是展示文案与代码能力不一致。
网页展示时也要分清输出位置。console.log 写到开发者工具;想显示在页面上,可以先放一个容器,再用文本节点追加内容:
<ul id="week-list"></ul>
<script>
const labels = ['星期一','星期二','星期三','星期四','星期五','星期六','星期日'];
const list = document.getElementById('week-list');
for (const label of labels) {
const item = document.createElement('li');
item.textContent = `星期标签:${label}`;
list.appendChild(item);
}
</script>
这里脚本位于容器之后,执行时能找到元素。用 textContent 是因为我们需要展示普通文字,不需要把标签当作 HTML 解析。这段页面例子表达的是渲染方法;下文的自动化断言验证的是日期逻辑,不把两者混为一谈。
二、getDay 的 0 是星期日
真正显示今天,可以从 new Date() 获取当前时刻。问题在于 getDay() 按本地时区返回星期编号,范围是 0 到 6,0 对应星期日;getDate() 返回的则是月内日期。二者名字相近,含义不同。
上面的数组以星期一开头。如果直接写 mondayFirst[now.getDay()],周日会显示星期一,其他日期也会错位。可以把编号转换成“周一从 0 开始”的下标:
const now = new Date();
const index = (now.getDay() + 6) % 7;
console.log(`今天是:${mondayFirst[index]}`);
推算一下就能发现原因:星期一的编号 1,转换后是 0;星期日的编号 0,转换后是 6。另一种办法是把数组改成“日、一、二、三、四、五、六”,直接用 getDay()。应让数组顺序与接口约定匹配,不要为了让某一天显示正确而随手加减一。
这个写法适合明确按运行环境本地时区展示的页面。若服务器部署在海外、用户分布在不同地区,就还缺少业务时区约定。
三、一个时刻可以对应两个不同的星期
用固定时刻做实验,比反复执行 new Date() 更容易复现。以下输入在 UTC 是 11 月 8 日晚间,在上海已经过了零点:
const instant = new Date('2026-11-08T16:30:00Z');
for (const timeZone of ['UTC', 'Asia/Shanghai']) {
const text = new Intl.DateTimeFormat('zh-CN', {
weekday: 'long',
timeZone
}).format(instant);
console.log(timeZone, text);
}
// UTC 星期日
// Asia/Shanghai 星期一
同一段代码也在华为云免费 AI DevSpace 的 AI Shell 中执行过,输出与上面一致。日期对象仍表示同一个时刻,变化的是我们观察它的时区。
这里的 zh-CN 控制显示语言,Asia/Shanghai 控制时区。中文界面不自动等于北京时间;语言参数和时区参数需要分别表达需求。个人本地日历可以跟随设备时区,统一按北京时间结算的业务页面则应显式指定时区,前后端采用同一规则。
服务端渲染与浏览器渲染也需要一致。如果服务端按 UTC 计算、浏览器按本地时间计算,午夜附近可能出现首次页面与更新后文字不同。排查时应记录同一个时间值和两端的时区设置,先核对输入,再判断显示逻辑。
四、把输入边界写进函数
可以把展示逻辑封装起来,让调用者传入 Date 对象和明确的时区。下面的函数适用于普通应用中当前 JavaScript 执行环境创建的 Date;跨 iframe 的对象传递需要另外约定数据格式。
function weekdayAt(date, timeZone = 'Asia/Shanghai') {
if (!(date instanceof Date)) {
throw new TypeError('请传入 Date 对象');
}
if (!Number.isFinite(date.getTime())) {
throw new RangeError('日期无效');
}
return new Intl.DateTimeFormat('zh-CN', {
weekday: 'long', timeZone
}).format(date);
}
console.log(`今天是:${weekdayAt(new Date())}`);
这里刻意不接受字符串自动转换,防止接口悄悄替调用者猜测日期格式。无效 Date 必须显式失败;时区名称无效时,Intl.DateTimeFormat 也会抛出异常。上层可以把异常转为“日期不可用”,不应兜底成星期日,因为星期日是一个真实结果。
还有一个常见边界:new Date('2026-11-09') 这样的标准纯日期字符串按 UTC 零点解释;它在洛杉矶对应前一天,因此显示星期日是可以复现的结果。若表达一个瞬间,接口可使用带 Z 或明确偏移量的日期时间字符串;若表达生日、账期等纯日历日期,应单独设计日期字段与时区规则,避免随意当作一个 UTC 瞬间处理。
例如下面两个字符串表示同一时刻:
const a = new Date('2026-11-08T16:30:00Z');
const b = new Date('2026-11-09T00:30:00+08:00');
console.log(a.getTime() === b.getTime()); // true
五、固定输入,验证最容易出错的边界
本次用 Node.js v26.3.0 执行了 24 项断言,覆盖七个星期的索引转换、错误索引反例、UTC/上海/洛杉矶的显示差异、上海零点前后一毫秒、纯日期解析、月份从零开始、无效日期、错误类型、错误时区,以及格式化不会修改原时间值。
24 项断言在系统默认时区下通过,又分别在 TZ=UTC 和 TZ=America/Los_Angeles 下通过。后两次用于检查代码是否意外依赖开发机时区;这些结果属于本次 Node 环境验证,不代表已经对所有浏览器或全部历史时区做了兼容性测试。
复制前面的 weekdayAt 后,下面这组关键断言可以先跑起来:
const assert = require('node:assert/strict');
assert.equal(weekdayAt(new Date('2026-11-08T16:30:00Z'), 'UTC'), '星期日');
assert.equal(weekdayAt(new Date('2026-11-08T16:30:00Z')), '星期一');
assert.equal(weekdayAt(new Date('2026-11-08T15:59:59.999Z')), '星期日');
assert.equal(weekdayAt(new Date('2026-11-08T16:00:00.000Z')), '星期一');
assert.throws(() => weekdayAt(new Date(NaN)), RangeError);
assert.throws(() => weekdayAt('2026-11-09'), TypeError);
console.log('6 项关键断言通过');
练习数组遍历时,先确保七个标签按预期输出;要展示真实的今天,再明确日期来源、索引约定和业务时区。这样从课堂小题走到实际页面,功能边界才是清楚的。
来源与参考
原题来自本人网站“安全问答”的星期数组遍历练习:https://www.cveoy.top/t/topic/bEmc 。本文基于该题重新组织说明并编写 JavaScript 示例,使用 AI 辅助整理,运行结果经过上述实测。
星期编号语义:MDN Date.prototype.getDay,https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getDay
日期解析边界:MDN Date.parse,https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/parse
语言与时区格式化:MDN Intl.DateTimeFormat,https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat
标准算法:ECMAScript Date.prototype.getDay,https://tc39.es/ecma262/multipage/numbers-and-dates.html#sec-date.prototype.getday
- 点赞
- 收藏
- 关注作者
评论(0)