同一份账单在一台电脑上显示 10 月 6 日,换到另一台却成了 10 月 5 日。把整个项目交给 Claude,让它“处理时区”,通常会扩大改动范围。更稳妥的顺序是:确定这个字段表示什么,保留一个失败输入,再选择转换方法。本文处理只有年月日的字段,适合账单日、生日和排期日期;带具体时刻的会议通知需要另外的时区约定。
一 交给 Claude 的最小证据
准备字段样例 2026-10-06、当前显示函数、运行环境、预期结果。不要上传真实生日或客户账单,使用虚构数据即可。下面这一行就是足够小的复现:
console.log(new Date('2026-10-06').getDate());
在支持 TZ 环境变量的终端中,可以分别运行 TZ=UTC node demo.mjs 和 TZ=America/Los_Angeles node demo.mjs。前者应为 6,后者应为 5。这里的变化来自先把日期字符串解析为 UTC 时间点,再读取运行环境中的本地日期。MDN 的 Date.parse 文档区分了只有日期的字符串,以及没有时区但含有时间的字符串,不能把两者当成相同输入。
二 先确认字段约定
问产品或接口负责人:这个值是否会因查看者所在地而改变?如果答案是否定的,就按日历日期保存与显示,不要无意中转成时间点。还要确认是否接受空值、允许哪些年份、非法日期应该报错还是留空。以下示例约定年份为 1000 至 9999,非法输入抛错,不自动修正为下个月。
保存为 date-only.mjs,运行 node date-only.mjs:
import assert from 'node:assert/strict';
function displayDate(value) {
if (typeof value !== 'string' ||
!/^[1-9]\d{3}-\d{2}-\d{2}$/.test(value)) {
throw new TypeError('日期格式必须为 YYYY-MM-DD');
}
const time = Date.parse(`${value}T00:00:00.000Z`);
if (!Number.isFinite(time) ||
new Date(time).toISOString().slice(0, 10) !== value) {
throw new RangeError('日期不存在');
}
const [y, m, d] = value.split('-').map(Number);
return `${y}年${m}月${d}日`;
}
assert.equal(displayDate('2026-10-06'), '2026年10月6日');
assert.equal(displayDate('2024-02-29'), '2024年2月29日');
assert.throws(() => displayDate('2026-02-29'));
assert.throws(() => displayDate('2026-13-01'));
assert.throws(() => displayDate(null));
console.log('date-only checks passed');
代码使用 UTC 只做合法性校验;实际显示直接使用年月日三个部分。因此查看者时区不参与最终文本生成。这里没有自动猜测 10/06/2026 的月日顺序,也没有掩盖后端发来无效值的问题。
三 可复制的 Claude 协作提示
请协助排查一个日历日期偏移问题。字段表示账单日期,不是时间点。 输入:2026-10-06;预期:任何时区都显示 2026年10月6日。 当前实现:new Date(value).getDate()。 约束:不新增依赖;仅接受 YYYY-MM-DD,年份 1000 至 9999;非法日期报错。 先指出能从代码证明的原因和仍需确认的信息,再给最小修复。 请列出 UTC、洛杉矶、上海三个时区的验证命令,并覆盖闰日、非法月份与空值。 不要声称运行过命令;把建议结果与实际测试记录分开。
得到回复后,先核对它有没有偷偷接受其他日期格式,再运行自己项目中的真实显示入口。只测试独立函数,不能证明表单、序列化或数据库层没有再次转换。
四 验收与适用边界
验收至少包括:三个时区显示一致、合法闰日通过、非法日期失败、原字段值未被改变。本文示例已在 Node.js 24.19.0 中执行,并分别检查上述三个时区;这不代表你的完整应用已经通过测试。若字段实际代表“会议开始时间”,应保存含偏移量的时间点,并明确展示时区,不能套用本篇的日期字符串方案。
调试结束,把失败样例和业务约定写入测试名称或接口文档。下次同事再加入日期库时,这条回归用例才会提醒他:此处不该发生时区转换。
五 如果最小示例通过,页面仍然错
顺着数据经过的路径逐层记录脱敏值:接口原文、状态存储、表单绑定和最终显示函数。每层都注明值是字符串、时间戳还是 Date 对象,避免只记录看起来相同的文本。若接口已经返回前一天,前端加一天只会遮住上游问题;若接口正确而表单提交后变了,应检查序列化位置。把第一处发生变化的边界和两侧样例交给 Claude,要求只修改这一处,再重复原来的时区检查。这样补丁的范围有证据支撑,也方便以后回退。
方法参考:Anthropic 提示工程概览。